mirror of
https://github.com/signerless/llm-checker.git
synced 2026-10-15 17:26:20 +00:00
Comprehensive Windows crash fix - handle ALL spawn ollama calls
Fixed remaining unprotected spawn('ollama') calls across multiple files:
- src/models/deterministic-selector.js: Added ENOENT error handling in runOllamaCommand and getModelDetails
- ml-model/js/cli.js: Protected getAvailableModels and runOllamaModel functions
- Added proper try-catch blocks around all spawn calls
- Added graceful fallbacks when Ollama executable is not found
- Enhanced error messages to guide users to install Ollama
This should completely resolve the Windows ENOENT crash when Ollama is not installed.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
9754f0d2bd
commit
a163ccba48
3 changed files with 99 additions and 49 deletions
|
|
@ -10,33 +10,45 @@ class OllamaAISelector {
|
|||
|
||||
async getAvailableModels() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ollama = spawn('ollama', ['list']);
|
||||
let output = '';
|
||||
let error = '';
|
||||
try {
|
||||
const ollama = spawn('ollama', ['list']);
|
||||
let output = '';
|
||||
let error = '';
|
||||
|
||||
ollama.stdout.on('data', (data) => {
|
||||
output += data.toString();
|
||||
});
|
||||
ollama.stdout.on('data', (data) => {
|
||||
output += data.toString();
|
||||
});
|
||||
|
||||
ollama.stderr.on('data', (data) => {
|
||||
error += data.toString();
|
||||
});
|
||||
ollama.stderr.on('data', (data) => {
|
||||
error += data.toString();
|
||||
});
|
||||
|
||||
ollama.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(`Ollama list failed: ${error}`));
|
||||
return;
|
||||
}
|
||||
ollama.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(`Ollama list failed: ${error}`));
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse ollama list output
|
||||
const lines = output.trim().split('\n').slice(1); // Skip header
|
||||
const models = lines
|
||||
.filter(line => line.trim())
|
||||
.map(line => line.split(/\s+/)[0])
|
||||
.filter(model => model && !model.includes('NAME'));
|
||||
// Parse ollama list output
|
||||
const lines = output.trim().split('\n').slice(1); // Skip header
|
||||
const models = lines
|
||||
.filter(line => line.trim())
|
||||
.map(line => line.split(/\s+/)[0])
|
||||
.filter(model => model && !model.includes('NAME'));
|
||||
|
||||
resolve(models);
|
||||
});
|
||||
resolve(models);
|
||||
});
|
||||
|
||||
ollama.on('error', (err) => {
|
||||
if (err.code === 'ENOENT') {
|
||||
reject(new Error('Ollama not found. Please install Ollama from https://ollama.ai'));
|
||||
} else {
|
||||
reject(new Error(`Ollama spawn error: ${err.message}`));
|
||||
}
|
||||
});
|
||||
} catch (spawnError) {
|
||||
reject(new Error(`Failed to start Ollama: ${spawnError.message}`));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -44,14 +56,15 @@ class OllamaAISelector {
|
|||
console.log(`🚀 Running Ollama with ${modelName}...`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const args = ['run', modelName];
|
||||
if (prompt) {
|
||||
args.push(prompt);
|
||||
}
|
||||
try {
|
||||
const args = ['run', modelName];
|
||||
if (prompt) {
|
||||
args.push(prompt);
|
||||
}
|
||||
|
||||
const ollama = spawn('ollama', args, {
|
||||
stdio: 'inherit' // Stream output directly to terminal
|
||||
});
|
||||
const ollama = spawn('ollama', args, {
|
||||
stdio: 'inherit' // Stream output directly to terminal
|
||||
});
|
||||
|
||||
ollama.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
|
|
@ -61,9 +74,16 @@ class OllamaAISelector {
|
|||
}
|
||||
});
|
||||
|
||||
ollama.on('error', (error) => {
|
||||
reject(new Error(`Failed to start Ollama: ${error.message}`));
|
||||
});
|
||||
ollama.on('error', (error) => {
|
||||
if (error.code === 'ENOENT') {
|
||||
reject(new Error('Ollama not found. Please install Ollama from https://ollama.ai'));
|
||||
} else {
|
||||
reject(new Error(`Failed to start Ollama: ${error.message}`));
|
||||
}
|
||||
});
|
||||
} catch (spawnError) {
|
||||
reject(new Error(`Failed to start Ollama: ${spawnError.message}`));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "llm-checker",
|
||||
"version": "2.3.2",
|
||||
"version": "2.3.3",
|
||||
"description": "Intelligent CLI tool with AI-powered model selection that analyzes your hardware and recommends optimal LLM models for your system",
|
||||
"bin": {
|
||||
"llm-checker": "bin/enhanced_cli.js"
|
||||
|
|
|
|||
|
|
@ -221,7 +221,8 @@ class DeterministicModelSelector {
|
|||
}
|
||||
|
||||
async getModelDetails(modelName) {
|
||||
const details = await this.runOllamaCommand(['show', modelName]);
|
||||
try {
|
||||
const details = await this.runOllamaCommand(['show', modelName]);
|
||||
|
||||
// Parse model details from ollama show output
|
||||
const meta = {
|
||||
|
|
@ -236,7 +237,22 @@ class DeterministicModelSelector {
|
|||
model_identifier: modelName
|
||||
};
|
||||
|
||||
return meta;
|
||||
return meta;
|
||||
} catch (error) {
|
||||
// If Ollama is not available or model details can't be fetched, return minimal info
|
||||
return {
|
||||
name: modelName,
|
||||
family: 'unknown',
|
||||
paramsB: 0,
|
||||
ctxMax: 2048,
|
||||
quant: 'unknown',
|
||||
sizeGB: 0,
|
||||
modalities: ['text'],
|
||||
tags: [],
|
||||
model_identifier: modelName,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -404,20 +420,34 @@ class DeterministicModelSelector {
|
|||
|
||||
async runOllamaCommand(args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn('ollama', args, { stdio: 'pipe' });
|
||||
let output = '';
|
||||
let error = '';
|
||||
|
||||
proc.stdout.on('data', (data) => output += data);
|
||||
proc.stderr.on('data', (data) => error += data);
|
||||
|
||||
proc.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve(output);
|
||||
} else {
|
||||
reject(new Error(`Ollama command failed: ${error}`));
|
||||
}
|
||||
});
|
||||
try {
|
||||
const proc = spawn('ollama', args, { stdio: 'pipe' });
|
||||
let output = '';
|
||||
let error = '';
|
||||
|
||||
proc.stdout.on('data', (data) => output += data);
|
||||
proc.stderr.on('data', (data) => error += data);
|
||||
|
||||
proc.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve(output);
|
||||
} else {
|
||||
reject(new Error(`Ollama command failed: ${error}`));
|
||||
}
|
||||
});
|
||||
|
||||
proc.on('error', (err) => {
|
||||
// Handle ENOENT and other spawn errors gracefully
|
||||
if (err.code === 'ENOENT') {
|
||||
reject(new Error('Ollama not found. Please install Ollama from https://ollama.ai'));
|
||||
} else {
|
||||
reject(new Error(`Ollama spawn error: ${err.message}`));
|
||||
}
|
||||
});
|
||||
} catch (spawnError) {
|
||||
// Handle synchronous spawn errors
|
||||
reject(new Error(`Failed to start Ollama: ${spawnError.message}`));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue