@yemi33/minions 0.1.1698 → 0.1.1699
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dashboard.js +33 -0
- package/engine/consolidation.js +4 -0
- package/engine/copilot-models.json +1 -1
- package/engine/kb-sweep.js +8 -0
- package/engine/llm.js +87 -4
- package/engine/pipeline.js +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dashboard.js
CHANGED
|
@@ -1825,6 +1825,7 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
|
|
|
1825
1825
|
if (onAbortReady) onAbortReady(p1.abort);
|
|
1826
1826
|
result = await p1;
|
|
1827
1827
|
llm.trackEngineUsage(label, result.usage);
|
|
1828
|
+
if (result.missingRuntime) return result;
|
|
1828
1829
|
|
|
1829
1830
|
if (result.text) {
|
|
1830
1831
|
updateSession(store, sessionKey, result.sessionId || sessionId, true);
|
|
@@ -1862,6 +1863,7 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
|
|
|
1862
1863
|
if (onAbortReady) onAbortReady(p2.abort);
|
|
1863
1864
|
result = await p2;
|
|
1864
1865
|
llm.trackEngineUsage(label, result.usage);
|
|
1866
|
+
if (result.missingRuntime) return result;
|
|
1865
1867
|
|
|
1866
1868
|
if (result.text) {
|
|
1867
1869
|
updateSession(store, sessionKey, result.sessionId, false);
|
|
@@ -1879,6 +1881,7 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
|
|
|
1879
1881
|
if (onAbortReady) onAbortReady(p3.abort);
|
|
1880
1882
|
result = await p3;
|
|
1881
1883
|
llm.trackEngineUsage(label, result.usage);
|
|
1884
|
+
if (result.missingRuntime) return result;
|
|
1882
1885
|
|
|
1883
1886
|
if (result.text) {
|
|
1884
1887
|
updateSession(store, sessionKey, result.sessionId, false);
|
|
@@ -1912,6 +1915,7 @@ async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext
|
|
|
1912
1915
|
if (onAbortReady) onAbortReady(p1.abort);
|
|
1913
1916
|
result = await p1;
|
|
1914
1917
|
llm.trackEngineUsage(label, result.usage);
|
|
1918
|
+
if (result.missingRuntime) return result;
|
|
1915
1919
|
|
|
1916
1920
|
if (result.text) {
|
|
1917
1921
|
updateSession(store, sessionKey, result.sessionId || sessionId, true);
|
|
@@ -1948,6 +1952,7 @@ async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext
|
|
|
1948
1952
|
if (onAbortReady) onAbortReady(p2.abort);
|
|
1949
1953
|
result = await p2;
|
|
1950
1954
|
llm.trackEngineUsage(label, result.usage);
|
|
1955
|
+
if (result.missingRuntime) return result;
|
|
1951
1956
|
|
|
1952
1957
|
if (result.text) {
|
|
1953
1958
|
updateSession(store, sessionKey, result.sessionId, false);
|
|
@@ -1966,6 +1971,7 @@ async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext
|
|
|
1966
1971
|
if (onAbortReady) onAbortReady(p3.abort);
|
|
1967
1972
|
result = await p3;
|
|
1968
1973
|
llm.trackEngineUsage(label, result.usage);
|
|
1974
|
+
if (result.missingRuntime) return result;
|
|
1969
1975
|
|
|
1970
1976
|
if (result.text) {
|
|
1971
1977
|
updateSession(store, sessionKey, result.sessionId, false);
|
|
@@ -2071,6 +2077,10 @@ async function ccDocCall({ message, document, title, filePath, selection, canEdi
|
|
|
2071
2077
|
if (session) session._docHash = docHash;
|
|
2072
2078
|
}
|
|
2073
2079
|
|
|
2080
|
+
if (result.missingRuntime) {
|
|
2081
|
+
return { answer: result.text || result.stderr || 'Minions runtime is not installed or configured.', content: null, actions: [] };
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2074
2084
|
if (result.code !== 0 || !result.text) {
|
|
2075
2085
|
console.error(`[doc-chat] Failed: code=${result.code}, empty=${!result.text}, filePath=${filePath}, stderr=${(result.stderr || '').slice(0, 200)}`);
|
|
2076
2086
|
return { answer: 'Failed to process request. Try again.', content: null, actions: [] };
|
|
@@ -2125,6 +2135,10 @@ async function ccDocCallStreaming({ message, document, title, filePath, selectio
|
|
|
2125
2135
|
if (session) session._docHash = docHash;
|
|
2126
2136
|
}
|
|
2127
2137
|
|
|
2138
|
+
if (result.missingRuntime) {
|
|
2139
|
+
return { answer: result.text || result.stderr || 'Minions runtime is not installed or configured.', content: null, actions: [] };
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2128
2142
|
if (result.code !== 0 || !result.text) {
|
|
2129
2143
|
console.error(`[doc-chat-stream] Failed: code=${result.code}, empty=${!result.text}, filePath=${filePath}, stderr=${(result.stderr || '').slice(0, 200)}`);
|
|
2130
2144
|
return { answer: 'Failed to process request. Try again.', content: null, actions: [] };
|
|
@@ -5054,6 +5068,13 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5054
5068
|
_ccHeartbeatTimer = null;
|
|
5055
5069
|
}
|
|
5056
5070
|
};
|
|
5071
|
+
const finishMissingRuntime = (result, liveState) => {
|
|
5072
|
+
const text = result.text || result.stderr || 'Minions runtime is not installed or configured.';
|
|
5073
|
+
liveState.donePayload = { type: 'done', text, actions: [], sessionId: null, missingRuntime: true };
|
|
5074
|
+
if (liveState.writer) liveState.writer(liveState.donePayload);
|
|
5075
|
+
if (liveState.endResponse) liveState.endResponse();
|
|
5076
|
+
_scheduleCcLiveCleanup(tabId);
|
|
5077
|
+
};
|
|
5057
5078
|
try {
|
|
5058
5079
|
const body = await readBody(req);
|
|
5059
5080
|
if (!body.message && !body.reconnect) { res.statusCode = 400; res.end('message required'); return; }
|
|
@@ -5176,6 +5197,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5176
5197
|
const result = await llmPromise;
|
|
5177
5198
|
trackUsage('command-center', result.usage);
|
|
5178
5199
|
|
|
5200
|
+
if (result.missingRuntime) {
|
|
5201
|
+
finishMissingRuntime(result, liveState);
|
|
5202
|
+
return;
|
|
5203
|
+
}
|
|
5204
|
+
|
|
5179
5205
|
// Handle failure — non-zero exit with text = max_turns or partial success, still usable
|
|
5180
5206
|
if (!result.text && wasResume && result.code !== 0 && !req.destroyed) {
|
|
5181
5207
|
// Resume failed (stale/expired session) — auto-retry as fresh session (skip if client already disconnected)
|
|
@@ -5198,6 +5224,10 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5198
5224
|
Object.assign(result, retryResult);
|
|
5199
5225
|
}
|
|
5200
5226
|
}
|
|
5227
|
+
if (result.missingRuntime) {
|
|
5228
|
+
finishMissingRuntime(result, liveState);
|
|
5229
|
+
return;
|
|
5230
|
+
}
|
|
5201
5231
|
if (!result.text) {
|
|
5202
5232
|
if (req.destroyed) { _ccStreamEnded = true; return; } // client already gone — nothing to send
|
|
5203
5233
|
const debugInfo = result.code !== 0 ? `(exit code ${result.code})` : '(empty response)';
|
|
@@ -5381,6 +5411,9 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5381
5411
|
model: 'haiku', maxTurns: 1, timeout: 30000, label: 'schedule-parse', direct: true,
|
|
5382
5412
|
engineConfig: CONFIG.engine,
|
|
5383
5413
|
});
|
|
5414
|
+
if (result.missingRuntime) {
|
|
5415
|
+
return jsonReply(res, 503, { error: result.text || result.stderr || 'Minions runtime is not installed or configured.', missingRuntime: true });
|
|
5416
|
+
}
|
|
5384
5417
|
const parsed = JSON.parse(result.text.trim());
|
|
5385
5418
|
if (!parsed.cron) return jsonReply(res, 422, { error: 'Could not parse schedule' });
|
|
5386
5419
|
return jsonReply(res, 200, { cron: parsed.cron, description: parsed.description || '' });
|
package/engine/consolidation.js
CHANGED
|
@@ -201,6 +201,10 @@ function consolidateWithLLM(items, existingNotes, files, config) {
|
|
|
201
201
|
if (_cleared) return;
|
|
202
202
|
clearTimeout(timeoutHandle);
|
|
203
203
|
trackEngineUsage('consolidation', result.usage);
|
|
204
|
+
if (result.missingRuntime) {
|
|
205
|
+
_fallback(`LLM consolidation skipped: ${result.text || result.stderr || 'runtime unavailable'} — falling back to regex`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
204
208
|
|
|
205
209
|
const extractedText = result.text || '';
|
|
206
210
|
const rawText = result.raw || '';
|
package/engine/kb-sweep.js
CHANGED
|
@@ -135,6 +135,10 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
|
|
|
135
135
|
engineConfig: opts.engineConfig,
|
|
136
136
|
});
|
|
137
137
|
trackEngineUsage('kb-sweep', result.usage);
|
|
138
|
+
if (result.missingRuntime) {
|
|
139
|
+
log('warn', `[kb-sweep] batch ${b + 1} LLM skipped: ${result.text || result.stderr || 'runtime unavailable'}`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
138
142
|
} catch (e) { log('warn', `[kb-sweep] batch ${b + 1} LLM error: ${e.message}`); continue; }
|
|
139
143
|
|
|
140
144
|
let batchPlan;
|
|
@@ -212,6 +216,10 @@ ${body}`;
|
|
|
212
216
|
engineConfig: opts.engineConfig,
|
|
213
217
|
});
|
|
214
218
|
trackEngineUsage('kb-sweep', result.usage);
|
|
219
|
+
if (result.missingRuntime) {
|
|
220
|
+
log('warn', `[kb-sweep] rewrite ${c.entry.category}/${c.entry.file} skipped: ${result.text || result.stderr || 'runtime unavailable'}`);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
215
223
|
let newBody = (result.text || '').trim();
|
|
216
224
|
// Strip accidental code fence
|
|
217
225
|
const fence = newBody.match(/^```(?:markdown|md)?\s*([\s\S]*?)```$/);
|
package/engine/llm.js
CHANGED
|
@@ -23,6 +23,7 @@ const { resolveRuntime } = require('./runtimes');
|
|
|
23
23
|
const MINIONS_DIR = shared.MINIONS_DIR;
|
|
24
24
|
const ENGINE_DIR = path.join(MINIONS_DIR, 'engine');
|
|
25
25
|
const COPILOT_TASK_COMPLETE_GRACE_MS = 3000;
|
|
26
|
+
const MISSING_RUNTIME_EXIT_CODE = 78;
|
|
26
27
|
|
|
27
28
|
// ─── Engine-Usage Metrics ────────────────────────────────────────────────────
|
|
28
29
|
|
|
@@ -96,6 +97,85 @@ function _resolveBin(runtime) {
|
|
|
96
97
|
|
|
97
98
|
function _resetBinCache() { _binCache.clear(); }
|
|
98
99
|
|
|
100
|
+
function _runtimeInstallHint(runtimeName, runtime) {
|
|
101
|
+
if (runtime && typeof runtime.installHint === 'string' && runtime.installHint) return runtime.installHint;
|
|
102
|
+
return `install the ${runtimeName || 'selected'} CLI and make sure it is on PATH`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function _missingRuntimeMessage(runtimeName, runtime, reason) {
|
|
106
|
+
const selected = runtime?.name || runtimeName || 'configured';
|
|
107
|
+
if (!runtime) {
|
|
108
|
+
return [
|
|
109
|
+
`Minions can't run the configured runtime "${selected}".`,
|
|
110
|
+
'',
|
|
111
|
+
reason || 'The configured runtime is not registered.',
|
|
112
|
+
'',
|
|
113
|
+
'Choose a supported runtime in Settings -> Engine -> defaultCli/ccCli, then install its CLI:',
|
|
114
|
+
'- Claude Code: npm install -g @anthropic-ai/claude-code or download from https://claude.ai/download',
|
|
115
|
+
'- GitHub Copilot CLI: install via GitHub CLI/gh-copilot or download from https://github.com/github/copilot-cli/releases',
|
|
116
|
+
'',
|
|
117
|
+
'After installing, restart Minions so the dashboard and engine inherit the updated PATH.',
|
|
118
|
+
].join('\n');
|
|
119
|
+
}
|
|
120
|
+
const lines = [
|
|
121
|
+
`Minions can't run the "${selected}" runtime yet.`,
|
|
122
|
+
'',
|
|
123
|
+
reason || `The ${selected} CLI binary was not found on PATH.`,
|
|
124
|
+
'',
|
|
125
|
+
`Install steps for "${selected}": ${_runtimeInstallHint(selected, runtime)}.`,
|
|
126
|
+
'',
|
|
127
|
+
'After installing, restart Minions so the dashboard and engine inherit the updated PATH.',
|
|
128
|
+
];
|
|
129
|
+
if (selected !== 'claude') {
|
|
130
|
+
lines.push('Or switch Settings -> Engine -> defaultCli/ccCli back to "claude" after installing Claude Code.');
|
|
131
|
+
} else {
|
|
132
|
+
lines.push('Or switch Settings -> Engine -> defaultCli/ccCli to "copilot" after installing GitHub Copilot CLI.');
|
|
133
|
+
}
|
|
134
|
+
return lines.join('\n');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function _missingRuntimeResult(runtimeName, runtime, reason) {
|
|
138
|
+
const message = _missingRuntimeMessage(runtimeName, runtime, reason);
|
|
139
|
+
return {
|
|
140
|
+
text: message,
|
|
141
|
+
usage: null,
|
|
142
|
+
sessionId: null,
|
|
143
|
+
code: MISSING_RUNTIME_EXIT_CODE,
|
|
144
|
+
stderr: message,
|
|
145
|
+
raw: '',
|
|
146
|
+
toolUses: [],
|
|
147
|
+
runtime: runtime?.name || runtimeName || null,
|
|
148
|
+
errorClass: shared.FAILURE_CLASS.CONFIG_ERROR,
|
|
149
|
+
missingRuntime: true,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function _resolvedCallResult(result) {
|
|
154
|
+
const promise = Promise.resolve(result);
|
|
155
|
+
promise.abort = () => {};
|
|
156
|
+
return promise;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function _resolveRuntimeNameFor(callOpts = {}) {
|
|
160
|
+
let runtimeName = callOpts.cli;
|
|
161
|
+
if (!runtimeName && callOpts.engineConfig) runtimeName = resolveCcCli(callOpts.engineConfig);
|
|
162
|
+
return runtimeName || 'claude';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function _runtimeUnavailableResult(callOpts = {}) {
|
|
166
|
+
const runtimeName = _resolveRuntimeNameFor(callOpts);
|
|
167
|
+
let runtime = null;
|
|
168
|
+
try {
|
|
169
|
+
runtime = resolveRuntime(runtimeName);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return _missingRuntimeResult(runtimeName, null, err.message);
|
|
172
|
+
}
|
|
173
|
+
if (!_resolveBin(runtime)) {
|
|
174
|
+
return _missingRuntimeResult(runtimeName, runtime, `The ${runtime.name} CLI binary was not found on PATH or in the runtime cache.`);
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
99
179
|
// ─── Spawn Helpers ───────────────────────────────────────────────────────────
|
|
100
180
|
|
|
101
181
|
/**
|
|
@@ -386,10 +466,7 @@ function _createStreamAccumulator({
|
|
|
386
466
|
function _resolveRuntimeFor(callOpts) {
|
|
387
467
|
// Explicit `cli` opt wins; otherwise fall to `engineConfig` resolution;
|
|
388
468
|
// otherwise default to claude (the historical behavior).
|
|
389
|
-
|
|
390
|
-
if (!runtimeName && callOpts.engineConfig) runtimeName = resolveCcCli(callOpts.engineConfig);
|
|
391
|
-
if (!runtimeName) runtimeName = 'claude';
|
|
392
|
-
return resolveRuntime(runtimeName);
|
|
469
|
+
return resolveRuntime(_resolveRuntimeNameFor(callOpts));
|
|
393
470
|
}
|
|
394
471
|
|
|
395
472
|
function _resolveModelFor(callOpts) {
|
|
@@ -434,6 +511,9 @@ function callLLM(promptText, sysPromptText, opts = {}) {
|
|
|
434
511
|
stream, disableBuiltinMcps, suppressAgentsMd, reasoningSummaries,
|
|
435
512
|
} = opts;
|
|
436
513
|
|
|
514
|
+
const unavailable = _runtimeUnavailableResult({ cli: cliOverride, engineConfig });
|
|
515
|
+
if (unavailable) return _resolvedCallResult(unavailable);
|
|
516
|
+
|
|
437
517
|
const runtime = _resolveRuntimeFor({ cli: cliOverride, engineConfig });
|
|
438
518
|
const model = _resolveModelForRuntime(runtime, { model: modelOverride, engineConfig });
|
|
439
519
|
const runtimeFeatureOpts = _resolveRuntimeFeatureOpts({
|
|
@@ -531,6 +611,9 @@ function callLLMStreaming(promptText, sysPromptText, opts = {}) {
|
|
|
531
611
|
stream, disableBuiltinMcps, suppressAgentsMd, reasoningSummaries,
|
|
532
612
|
} = opts;
|
|
533
613
|
|
|
614
|
+
const unavailable = _runtimeUnavailableResult({ cli: cliOverride, engineConfig });
|
|
615
|
+
if (unavailable) return _resolvedCallResult(unavailable);
|
|
616
|
+
|
|
534
617
|
const runtime = _resolveRuntimeFor({ cli: cliOverride, engineConfig });
|
|
535
618
|
const model = _resolveModelForRuntime(runtime, { model: modelOverride, engineConfig });
|
|
536
619
|
const runtimeFeatureOpts = _resolveRuntimeFeatureOpts({
|
package/engine/pipeline.js
CHANGED
|
@@ -488,7 +488,9 @@ async function executePlanStage(stage, stageState, run, config) {
|
|
|
488
488
|
timeout: 120000, label: 'pipeline-plan', model: 'sonnet', maxTurns: 1,
|
|
489
489
|
engineConfig: config.engine,
|
|
490
490
|
});
|
|
491
|
-
if (result.
|
|
491
|
+
if (result.missingRuntime) {
|
|
492
|
+
log('warn', `Pipeline plan LLM skipped: ${result.text || result.stderr || 'runtime unavailable'} — falling back to raw meeting context`);
|
|
493
|
+
} else if (result.text) {
|
|
492
494
|
content = result.text;
|
|
493
495
|
log('info', `Pipeline plan: LLM generated ${content.length} chars from meeting context`);
|
|
494
496
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1699",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|