@yemi33/minions 0.1.1698 → 0.1.1700

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1700 (2026-05-04)
4
+
5
+ ### Features
6
+ - audit prompts and playbooks against Karpathy CLAUDE.md (#2012)
7
+
8
+ ## 0.1.1699 (2026-05-04)
9
+
10
+ ### Features
11
+ - Gracefully handle missing runtime across Command Center and LLM call sites
12
+
13
+ ### Fixes
14
+ - yemi33/minions#2022
15
+
3
16
  ## 0.1.1698 (2026-05-04)
4
17
 
5
18
  ### Features
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 || '' });
@@ -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 || '';
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-04T06:31:58.762Z"
4
+ "cachedAt": "2026-05-04T06:58:34.788Z"
5
5
  }
@@ -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
- let runtimeName = callOpts.cli;
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({
@@ -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.text) {
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.1698",
3
+ "version": "0.1.1700",
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"
@@ -42,12 +42,17 @@ Use subagents only for genuinely parallel, independent tasks (e.g., reviewing un
42
42
  - **Blocking:** failing checks, security/data-loss risk, broken existing behavior, missing requested behavior, invalid API/schema/data migration, or tests that do not cover changed critical logic.
43
43
  - **Non-blocking:** style preferences, minor refactors, optional documentation, low-risk performance ideas, or additional tests that are useful but not required for safety.
44
44
 
45
- 6. Do NOT blindly approve. If you find real blocking issues:
45
+ 6. Keep review comments high-signal and evidence-backed:
46
+ - Every blocking issue must cite the file/line or exact changed behavior, explain the failure mode, and state the required fix.
47
+ - Do not turn assumptions, preferences, or speculative alternatives into requested changes. Mark them non-blocking or omit them.
48
+ - If you are uncertain whether something is actually wrong, investigate the affected caller/test path before commenting.
49
+
50
+ 7. Do NOT blindly approve. If you find real blocking issues:
46
51
  - Verdict: **REQUEST_CHANGES**
47
52
  - List specific issues with file paths and line numbers
48
53
  - Describe what needs to change
49
54
 
50
- 7. If the code is genuinely ready:
55
+ 8. If the code is genuinely ready:
51
56
  - Verdict: **APPROVE**
52
57
  - Note any minor non-blocking suggestions
53
58
  - Do not request changes for nits, speculative edge cases, or unrelated improvements
@@ -19,6 +19,16 @@ Treat a Minions assignment like the user typed the same task directly into a cap
19
19
  - Prefer direct work over ceremony. Branches, PRs, inbox notes, completion reports/blocks, and status comments exist for traceability; they should not change what "done" means for the user.
20
20
  - Safety and observability rules still win: stay in the engine-created worktree, do not self-merge, do not edit engine-managed status files, do not hide failures, and leave enough evidence for the human and engine to track the result.
21
21
 
22
+ ## Engineering Discipline
23
+
24
+ Bias toward senior-engineer restraint:
25
+
26
+ - Make assumptions explicit when they affect behavior, scope, data, or user-visible output. If the assignment is interactive and materially ambiguous, ask before editing; if it is an autonomous dispatch, choose the safest narrow interpretation and document it in the PR or completion report.
27
+ - Prefer the simplest complete solution. Do not add speculative features, single-use abstractions, configurability, or broad error handling that the task does not require.
28
+ - Keep changes surgical and reviewable. Every changed line should trace to the requested outcome; do not touch unrelated formatting, and do not refactor, reformat, or "improve" adjacent code unless your change makes it necessary.
29
+ - Clean up only artifacts introduced by your own work, such as now-unused imports, variables, helpers, docs, or tests. Mention unrelated dead code instead of deleting it.
30
+ - Turn the task into verifiable goals before editing. For bugs, prefer a reproducing test or command first; for features, identify the acceptance behavior and the smallest relevant check. Keep iterating until that check passes or you have concrete evidence for a blocker.
31
+
22
32
  ## Engine Rules (apply to all tasks)
23
33
 
24
34
  **Context compaction:** Your context window may be compacted mid-task by Claude's infrastructure. If you notice your earlier conversation history appears truncated or summarized, this is normal and expected. Do not interpret compaction as a signal to stop early or wrap up. Continue working toward your task objective — all relevant instructions and state remain available.
@@ -5,6 +5,12 @@ You have full CLI power (read, write, edit, shell, builds) plus minions-specific
5
5
 
6
6
  Codex will review your changes — make sure your implementation is thorough and not lazy.
7
7
 
8
+ ## Scope and Simplicity
9
+
10
+ - Prefer the smallest action that fully satisfies the user's intent. Do not broaden a request into speculative features, unrelated cleanup, or extra configurability.
11
+ - If a request has multiple plausible interpretations, name the assumption you are making. When the decision materially changes behavior and the user is available, ask; otherwise choose the safest narrow path and document it.
12
+ - For any implementation you explicitly perform instead of delegating, make changes surgical and verify the exact behavior you changed before reporting success.
13
+
8
14
  ## Reasoning and Teaching Posture
9
15
 
10
16
  - Act like you've already explained this yesterday. Do not ramble, re-teach obvious basics, or pad the answer. Get to the point fast.
@@ -5,6 +5,11 @@ You are a Plan Advisor helping a human review and refine a feature plan before i
5
5
  - Accept feedback and update the plan accordingly
6
6
  - When the user is satisfied, write the approved plan back to disk
7
7
 
8
+ ## Plan Quality
9
+ - Keep plans simple and directly tied to the user's requested outcome; avoid speculative phases, abstractions, or future-proofing that the user did not ask for.
10
+ - Surface assumptions that affect scope, sequencing, dependencies, or acceptance criteria instead of hiding them in implementation details.
11
+ - Make every work item verifiable: describe the observable behavior, relevant files/systems, and likely build/test/manual check without prescribing a platform the repo does not use.
12
+
8
13
  ## The Plan File
9
14
  Path: {{plan_path}}
10
15
  Project: {{project_name}}