@yemi33/minions 0.1.1587 → 0.1.1589
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 +10 -0
- package/bin/minions.js +5 -3
- package/dashboard/js/settings.js +216 -22
- package/dashboard.js +136 -8
- package/docs/copilot-cli-schema.md +637 -0
- package/docs/copilot-output-sample-claude.jsonl +72 -0
- package/docs/copilot-output-sample-default.jsonl +26 -0
- package/docs/copilot-output-sample-gpt4o.jsonl +23 -0
- package/engine/cli.js +250 -18
- package/engine/lifecycle.js +14 -9
- package/engine/llm.js +346 -94
- package/engine/model-discovery.js +167 -0
- package/engine/preflight.js +247 -19
- package/engine/runtimes/claude.js +413 -0
- package/engine/runtimes/copilot.js +566 -0
- package/engine/runtimes/index.js +61 -0
- package/engine/shared.js +299 -63
- package/engine/spawn-agent.js +265 -181
- package/engine.js +118 -31
- package/package.json +1 -1
package/engine.js
CHANGED
|
@@ -27,6 +27,7 @@ const shared = require('./engine/shared');
|
|
|
27
27
|
const { exec, execAsync, execSilent, runFile, ts, ENGINE_DEFAULTS,
|
|
28
28
|
WI_STATUS, DONE_STATUSES, WORK_TYPE, PLAN_STATUS, PRD_ITEM_STATUS, PRD_MATERIALIZABLE, PR_STATUS, DISPATCH_RESULT, AGENT_STATUS,
|
|
29
29
|
FAILURE_CLASS } = shared;
|
|
30
|
+
const { resolveRuntime } = require('./engine/runtimes');
|
|
30
31
|
const queries = require('./engine/queries');
|
|
31
32
|
|
|
32
33
|
// ─── Paths ──────────────────────────────────────────────────────────────────
|
|
@@ -245,6 +246,54 @@ function _maxTurnsForType(type, engineConfig) {
|
|
|
245
246
|
return globalOverride || _MAX_TURNS_BY_TYPE[type] || ENGINE_DEFAULTS.maxTurns;
|
|
246
247
|
}
|
|
247
248
|
|
|
249
|
+
// ─── Runtime adapter integration (P-2a6d9c4f) ────────────────────────────────
|
|
250
|
+
//
|
|
251
|
+
// _buildAgentSpawnFlags translates a resolved opts bag into the named CLI
|
|
252
|
+
// flags consumed by `engine/spawn-agent.js`. spawn-agent.js parses these back
|
|
253
|
+
// into an opts object and calls `runtime.buildArgs(opts)` once — keeping the
|
|
254
|
+
// adapter as the single source of truth for CLI-level flag formatting and
|
|
255
|
+
// avoiding double-emission.
|
|
256
|
+
//
|
|
257
|
+
// Capability gating happens HERE (in engine.js), not in the adapter:
|
|
258
|
+
// - Runtimes that don't support a feature (Copilot has no budgetCap, no
|
|
259
|
+
// bareMode, no fallbackModel) never see the flag. The adapter doesn't
|
|
260
|
+
// have to silently drop opts it can't honor.
|
|
261
|
+
// - Truly cross-runtime opts (model, maxTurns, allowedTools, effort,
|
|
262
|
+
// sessionId) are emitted whenever set; capability flags filter the
|
|
263
|
+
// ones that are runtime-specific.
|
|
264
|
+
// - Copilot-specific opts (`stream`, `disableBuiltinMcps`,
|
|
265
|
+
// `suppressAgentsMd`, `reasoningSummaries`) are emitted unconditionally;
|
|
266
|
+
// the Claude adapter ignores them via the "tolerate unknown opts" rule.
|
|
267
|
+
|
|
268
|
+
function _buildAgentSpawnFlags(runtime, opts = {}) {
|
|
269
|
+
const caps = (runtime && runtime.capabilities) || {};
|
|
270
|
+
const flags = ['--runtime', String(runtime?.name || 'claude')];
|
|
271
|
+
|
|
272
|
+
// Always-applicable: every runtime understands these.
|
|
273
|
+
if (opts.maxTurns != null) flags.push('--max-turns', String(opts.maxTurns));
|
|
274
|
+
if (opts.model) flags.push('--model', String(opts.model));
|
|
275
|
+
if (opts.allowedTools) flags.push('--allowedTools', String(opts.allowedTools));
|
|
276
|
+
|
|
277
|
+
// Capability-gated. The first three (effort/resume) gate on whether the
|
|
278
|
+
// runtime exposes the feature at all; the next three gate on whether the
|
|
279
|
+
// runtime's CLI surface actually accepts the flag.
|
|
280
|
+
if (caps.effortLevels && opts.effort) flags.push('--effort', String(opts.effort));
|
|
281
|
+
if (caps.sessionResume && opts.sessionId) flags.push('--resume', String(opts.sessionId));
|
|
282
|
+
if (caps.budgetCap && opts.maxBudget != null) flags.push('--max-budget-usd', String(opts.maxBudget));
|
|
283
|
+
if (caps.bareMode && opts.bare === true) flags.push('--bare');
|
|
284
|
+
if (caps.fallbackModel && opts.fallbackModel) flags.push('--fallback-model', String(opts.fallbackModel));
|
|
285
|
+
|
|
286
|
+
// Copilot-specific opts. Always emitted when set; the Claude adapter
|
|
287
|
+
// silently ignores them (per the "tolerate unknown opts" rule from
|
|
288
|
+
// P-7e3a8b1c). Engine code never branches on `runtime.name`.
|
|
289
|
+
if (opts.stream != null && opts.stream !== '') flags.push('--stream', String(opts.stream));
|
|
290
|
+
if (opts.disableBuiltinMcps === true) flags.push('--disable-builtin-mcps');
|
|
291
|
+
if (opts.suppressAgentsMd === true) flags.push('--no-custom-instructions');
|
|
292
|
+
if (opts.reasoningSummaries === true) flags.push('--enable-reasoning-summaries');
|
|
293
|
+
|
|
294
|
+
return flags;
|
|
295
|
+
}
|
|
296
|
+
|
|
248
297
|
// Resolve dependency plan item IDs to their PR branches
|
|
249
298
|
function resolveDependencyBranches(depIds, sourcePlan, project, config) {
|
|
250
299
|
const results = []; // [{ branch, prId }]
|
|
@@ -813,27 +862,27 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
813
862
|
log('warn', `Agent ${agentId} running ${type} task in main repo (no worktree) for ${id} — changes may land on master directly`);
|
|
814
863
|
}
|
|
815
864
|
|
|
816
|
-
//
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
//
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
// Session resume:
|
|
865
|
+
// ── Runtime + opts resolution (P-2a6d9c4f) ────────────────────────────────
|
|
866
|
+
// Every CLI-specific knob flows through the runtime adapter resolved from
|
|
867
|
+
// resolveAgentCli(agent, engine). Engine code MUST NOT branch on
|
|
868
|
+
// `runtime.name === ...`; capability flags gate runtime-specific features.
|
|
869
|
+
const agentConfig = config.agents?.[agentId] || null;
|
|
870
|
+
const runtime = resolveRuntime(shared.resolveAgentCli(agentConfig, engineConfig));
|
|
871
|
+
const runtimeName = runtime.name;
|
|
872
|
+
const resolvedModel = runtime.resolveModel(shared.resolveAgentModel(agentConfig, engineConfig));
|
|
873
|
+
const resolvedMaxBudget = shared.resolveAgentMaxBudget(agentConfig, engineConfig);
|
|
874
|
+
const resolvedBare = shared.resolveAgentBareMode(agentConfig, engineConfig);
|
|
875
|
+
|
|
876
|
+
// Effort: use 'low' for fast work types unless configured otherwise.
|
|
877
|
+
// The capability gate happens inside _buildAgentSpawnFlags — runtimes
|
|
878
|
+
// without effortLevels never see the flag.
|
|
879
|
+
const requestedEffort = engineConfig.agentEffort || (_FAST_WORK_TYPES.has(type) ? 'low' : null);
|
|
880
|
+
|
|
881
|
+
// Session resume: gated on `runtime.capabilities.sessionResume`. Same branch
|
|
882
|
+
// means the agent is continuing work on the same PR/feature (e.g., author
|
|
883
|
+
// fixing their own build failure).
|
|
833
884
|
let cachedSessionId = null;
|
|
834
|
-
|
|
835
|
-
// continuing work on the same PR/feature (e.g., author fixing their own build failure)
|
|
836
|
-
if (!agentId.startsWith('temp-')) {
|
|
885
|
+
if (runtime.capabilities.sessionResume && !agentId.startsWith('temp-')) {
|
|
837
886
|
try {
|
|
838
887
|
const sessionFile = safeJson(path.join(AGENTS_DIR, agentId, 'session.json'));
|
|
839
888
|
if (sessionFile?.sessionId && sessionFile.savedAt) {
|
|
@@ -841,13 +890,30 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
841
890
|
const sameBranch = branchName && sessionFile.branch && sessionFile.branch === branchName;
|
|
842
891
|
if (sessionAge < 2 * 60 * 60 * 1000 && sameBranch) {
|
|
843
892
|
cachedSessionId = sessionFile.sessionId;
|
|
844
|
-
args.push('--resume', sessionFile.sessionId);
|
|
845
893
|
log('info', `Resuming session ${sessionFile.sessionId} for ${agentId} on branch ${branchName} (age: ${Math.round(sessionAge / 60000)}min)`);
|
|
846
894
|
}
|
|
847
895
|
}
|
|
848
896
|
} catch (e) { log('warn', 'session resume lookup: ' + e.message); }
|
|
849
897
|
}
|
|
850
898
|
|
|
899
|
+
// Build the spawn-agent.js flag bag. spawn-agent parses the named flags
|
|
900
|
+
// back into an opts object and calls runtime.buildArgs(opts) — so the
|
|
901
|
+
// adapter is the single source of truth for the actual CLI args.
|
|
902
|
+
const args = _buildAgentSpawnFlags(runtime, {
|
|
903
|
+
model: resolvedModel,
|
|
904
|
+
maxTurns: _maxTurnsForType(type, engineConfig),
|
|
905
|
+
allowedTools: claudeConfig.allowedTools,
|
|
906
|
+
effort: requestedEffort,
|
|
907
|
+
sessionId: cachedSessionId,
|
|
908
|
+
maxBudget: resolvedMaxBudget,
|
|
909
|
+
bare: resolvedBare,
|
|
910
|
+
fallbackModel: engineConfig.claudeFallbackModel,
|
|
911
|
+
stream: engineConfig.copilotStreamMode,
|
|
912
|
+
disableBuiltinMcps: engineConfig.copilotDisableBuiltinMcps,
|
|
913
|
+
suppressAgentsMd: engineConfig.copilotSuppressAgentsMd,
|
|
914
|
+
reasoningSummaries: engineConfig.copilotReasoningSummaries,
|
|
915
|
+
});
|
|
916
|
+
|
|
851
917
|
// MCP servers: agents inherit from ~/.claude.json directly as Claude Code processes.
|
|
852
918
|
// No --mcp-config needed — avoids redundant config and ensures agents always have latest servers.
|
|
853
919
|
|
|
@@ -1060,15 +1126,32 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1060
1126
|
return;
|
|
1061
1127
|
}
|
|
1062
1128
|
|
|
1063
|
-
//
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
'
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1129
|
+
// Steering resume — gated on `runtime.capabilities.sessionResume`. If the
|
|
1130
|
+
// runtime can't resume sessions, fail fast: nothing to spawn here.
|
|
1131
|
+
if (!runtime.capabilities.sessionResume) {
|
|
1132
|
+
log('warn', `Steering: runtime ${runtime.name} does not support session resume — skipping for ${agentId}`);
|
|
1133
|
+
try { fs.appendFileSync(liveOutputPath, `\n[steering-failed] Runtime ${runtime.name} does not support session resume. Message was: ${steerMsg}\n`); } catch {}
|
|
1134
|
+
try { fs.unlinkSync(steerPromptPath); } catch {}
|
|
1135
|
+
activeProcesses.delete(id);
|
|
1136
|
+
completeDispatch(id, DISPATCH_RESULT.SUCCESS, 'Steering not supported by runtime', '', { processWorkItemFailure: false });
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// Reuse the same flag-builder used by the main spawn so capability gates
|
|
1141
|
+
// and runtime-specific opts stay consistent across the two paths.
|
|
1142
|
+
const resumeArgs = _buildAgentSpawnFlags(runtime, {
|
|
1143
|
+
model: resolvedModel,
|
|
1144
|
+
maxTurns: engineConfig?.maxTurns || ENGINE_DEFAULTS.maxTurns,
|
|
1145
|
+
allowedTools: claudeConfig?.allowedTools,
|
|
1146
|
+
sessionId: steerSessionId,
|
|
1147
|
+
maxBudget: resolvedMaxBudget,
|
|
1148
|
+
bare: resolvedBare,
|
|
1149
|
+
fallbackModel: engineConfig?.claudeFallbackModel,
|
|
1150
|
+
stream: engineConfig?.copilotStreamMode,
|
|
1151
|
+
disableBuiltinMcps: engineConfig?.copilotDisableBuiltinMcps,
|
|
1152
|
+
suppressAgentsMd: engineConfig?.copilotSuppressAgentsMd,
|
|
1153
|
+
reasoningSummaries: engineConfig?.copilotReasoningSummaries,
|
|
1154
|
+
});
|
|
1072
1155
|
|
|
1073
1156
|
const spawnScript = path.join(ENGINE_DIR, 'spawn-agent.js');
|
|
1074
1157
|
const childEnv = shared.cleanChildEnv();
|
|
@@ -1354,6 +1437,10 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1354
1437
|
if (idx < 0) return dispatch;
|
|
1355
1438
|
const item = dispatch.pending.splice(idx, 1)[0];
|
|
1356
1439
|
item.started_at = startedAt;
|
|
1440
|
+
// Persist the resolved runtime so post-completion hooks (lifecycle.js) can
|
|
1441
|
+
// route output parsing through the right adapter. Also surfaces the choice
|
|
1442
|
+
// in dispatch.json for debugging multi-runtime fleets.
|
|
1443
|
+
item.runtimeName = runtimeName;
|
|
1357
1444
|
delete item.skipReason;
|
|
1358
1445
|
delete item._agentBusySince;
|
|
1359
1446
|
if (!dispatch.active.some(d => d.id === id)) {
|
|
@@ -3786,7 +3873,7 @@ module.exports = {
|
|
|
3786
3873
|
reconcileItemsWithPrs, detectDependencyCycles,
|
|
3787
3874
|
parseConflictFiles, pruneAncestorDeps, preflightMergeSimulation, // exported for testing
|
|
3788
3875
|
isWorktreeRetryableError, removeStaleIndexLock, // exported for testing
|
|
3789
|
-
_maxTurnsForType, buildProjectContext, normalizeAc, // exported for testing
|
|
3876
|
+
_maxTurnsForType, buildProjectContext, normalizeAc, _buildAgentSpawnFlags, // exported for testing
|
|
3790
3877
|
|
|
3791
3878
|
// Playbooks
|
|
3792
3879
|
renderPlaybook, validatePlaybookVars, PLAYBOOK_REQUIRED_VARS, buildWorkItemDispatchVars,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1589",
|
|
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"
|