@yemi33/minions 0.1.1740 → 0.1.1742
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 +15 -6
- package/dashboard.js +70 -8
- package/engine/cli.js +35 -17
- package/engine/copilot-models.json +1 -1
- package/engine/meeting.js +26 -1
- package/engine/shared.js +2 -1
- package/engine.js +20 -2
- package/package.json +1 -1
- package/prompts/cc-system.md +25 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.1742 (2026-05-06)
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
- pending-reassignment double-books agent with own pending dispatch (#2108)
|
|
7
|
+
|
|
8
|
+
## 0.1.1741 (2026-05-06)
|
|
4
9
|
|
|
5
10
|
### Features
|
|
6
|
-
-
|
|
7
|
-
-
|
|
11
|
+
- hard-timeout backstop prevents permanent round stalls
|
|
12
|
+
- auto-index API + CLI catalog into preamble; threshold-based delegation gate
|
|
8
13
|
|
|
9
|
-
###
|
|
10
|
-
-
|
|
11
|
-
|
|
14
|
+
### Other
|
|
15
|
+
- chore(gitignore): ignore .vscode/, engine/completions/, pull-requests.json.backup
|
|
16
|
+
|
|
17
|
+
## 0.1.1739 (2026-05-06)
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
- make Command Center chat sessions non-expiring (#2100)
|
|
12
21
|
|
|
13
22
|
## 0.1.1738 (2026-05-06)
|
|
14
23
|
|
package/dashboard.js
CHANGED
|
@@ -1176,6 +1176,50 @@ let _preambleCache = null;
|
|
|
1176
1176
|
let _preambleCacheTs = 0;
|
|
1177
1177
|
const PREAMBLE_TTL = 30000; // 30s — longer TTL since preamble is lightweight orientation, not real-time data
|
|
1178
1178
|
|
|
1179
|
+
// SoT for CC's runtime API index. Captured lazily on the first HTTP request
|
|
1180
|
+
// because ROUTES is closed over inside the request handler. Subsequent
|
|
1181
|
+
// captures no-op via the truthy guard.
|
|
1182
|
+
let _ccApiRoutesMeta = null;
|
|
1183
|
+
|
|
1184
|
+
function _routesAsMeta(routes) {
|
|
1185
|
+
return routes.map(r => ({
|
|
1186
|
+
method: r.method,
|
|
1187
|
+
path: typeof r.path === 'string' ? r.path : String(r.path),
|
|
1188
|
+
desc: r.desc || '',
|
|
1189
|
+
params: r.params || null,
|
|
1190
|
+
}));
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
function _captureApiRoutesMeta(routes) {
|
|
1194
|
+
if (_ccApiRoutesMeta || !Array.isArray(routes)) return;
|
|
1195
|
+
_ccApiRoutesMeta = _routesAsMeta(routes);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
function _formatCcApiRoutesIndex() {
|
|
1199
|
+
if (!Array.isArray(_ccApiRoutesMeta) || _ccApiRoutesMeta.length === 0) return '';
|
|
1200
|
+
return _ccApiRoutesMeta
|
|
1201
|
+
.filter(r => r.path.startsWith('/api/'))
|
|
1202
|
+
.map(r => {
|
|
1203
|
+
const params = r.params ? ` — params: ${r.params}` : '';
|
|
1204
|
+
return `- \`${r.method} ${r.path}\` — ${r.desc}${params}`;
|
|
1205
|
+
})
|
|
1206
|
+
.join('\n');
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
const { CLI_COMMAND_DOCS: _CC_CLI_DOCS } = require('./engine/cli');
|
|
1210
|
+
|
|
1211
|
+
function _formatCcCliCommandsIndex() {
|
|
1212
|
+
if (!_CC_CLI_DOCS) return '';
|
|
1213
|
+
return Object.entries(_CC_CLI_DOCS)
|
|
1214
|
+
.map(([name, { args, summary }]) => `- \`minions ${name}${args ? ' ' + args : ''}\` — ${summary}`)
|
|
1215
|
+
.join('\n');
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
function _resetPreambleCache() {
|
|
1219
|
+
_preambleCache = null;
|
|
1220
|
+
_preambleCacheTs = 0;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1179
1223
|
function buildCCStatePreamble() {
|
|
1180
1224
|
const now = Date.now();
|
|
1181
1225
|
if (_preambleCache && now - _preambleCacheTs < PREAMBLE_TTL) return _preambleCache;
|
|
@@ -1198,6 +1242,19 @@ function buildCCStatePreamble() {
|
|
|
1198
1242
|
let pipelineCount = 0;
|
|
1199
1243
|
try { pipelineCount = require('./engine/pipeline').getPipelines().length; } catch {}
|
|
1200
1244
|
|
|
1245
|
+
const apiIndex = _formatCcApiRoutesIndex();
|
|
1246
|
+
const cliIndex = _formatCcCliCommandsIndex();
|
|
1247
|
+
const indexSection = (apiIndex || cliIndex) ? `
|
|
1248
|
+
|
|
1249
|
+
### API Index (auto-generated from dashboard.js ROUTES — single source of truth)
|
|
1250
|
+
${apiIndex || '(routes not yet captured — first request still pending)'}
|
|
1251
|
+
|
|
1252
|
+
### CLI Index (auto-generated from engine/cli.js CLI_COMMAND_DOCS — single source of truth)
|
|
1253
|
+
${cliIndex || '(unavailable)'}
|
|
1254
|
+
|
|
1255
|
+
For any \`/api/...\` endpoint not covered by a named CC action, use the generic fallback:
|
|
1256
|
+
\`{"type":"<descriptive>","endpoint":"/api/...","params":{...}}\`.` : '';
|
|
1257
|
+
|
|
1201
1258
|
const result = `### Agents
|
|
1202
1259
|
${agents}
|
|
1203
1260
|
|
|
@@ -1211,8 +1268,8 @@ PRs: ${prCount} | Work items: ${wiCount} | Plans/PRDs: ${planFiles.length} | Sch
|
|
|
1211
1268
|
### Projects
|
|
1212
1269
|
${projects}
|
|
1213
1270
|
|
|
1214
|
-
Use tools to read \`config.json\` (schedules), \`pipelines/\` dir
|
|
1215
|
-
For all state files, look under \`${MINIONS_DIR}
|
|
1271
|
+
Use tools to read \`config.json\` (schedules), \`pipelines/\` dir for details.
|
|
1272
|
+
For all state files, look under \`${MINIONS_DIR}\`.${indexSection}`;
|
|
1216
1273
|
_preambleCache = result;
|
|
1217
1274
|
_preambleCacheTs = now;
|
|
1218
1275
|
return result;
|
|
@@ -6546,12 +6603,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6546
6603
|
});
|
|
6547
6604
|
}},
|
|
6548
6605
|
{ method: 'GET', path: '/api/routes', desc: 'List all available API endpoints', handler: (req, res) => {
|
|
6549
|
-
const list = ROUTES.map(
|
|
6550
|
-
method: r.method,
|
|
6551
|
-
path: typeof r.path === 'string' ? r.path : r.path.toString(),
|
|
6552
|
-
description: r.desc,
|
|
6553
|
-
params: r.params || null
|
|
6554
|
-
}));
|
|
6606
|
+
const list = _routesAsMeta(ROUTES).map(({ desc, ...rest }) => ({ ...rest, description: desc }));
|
|
6555
6607
|
return jsonReply(res, 200, { routes: list });
|
|
6556
6608
|
}},
|
|
6557
6609
|
|
|
@@ -7184,6 +7236,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
7184
7236
|
|
|
7185
7237
|
// ── Route Dispatcher ────────────────────────────────────────────────────────
|
|
7186
7238
|
|
|
7239
|
+
// Capture ROUTES metadata into the module-level snapshot so CC's preamble
|
|
7240
|
+
// renders the live API surface (single source of truth — adding any new
|
|
7241
|
+
// route to ROUTES above auto-surfaces it in CC's index).
|
|
7242
|
+
_captureApiRoutesMeta(ROUTES);
|
|
7243
|
+
|
|
7187
7244
|
const pathname = req.url.split('?')[0];
|
|
7188
7245
|
const _reqStart = Date.now();
|
|
7189
7246
|
for (const route of ROUTES) {
|
|
@@ -7269,6 +7326,11 @@ module.exports = {
|
|
|
7269
7326
|
_resolveWorkItemsCreateTarget: resolveWorkItemsCreateTarget,
|
|
7270
7327
|
_createPipelineFromAction: createPipelineFromAction,
|
|
7271
7328
|
executeCCActions,
|
|
7329
|
+
buildCCStatePreamble,
|
|
7330
|
+
_captureApiRoutesMeta,
|
|
7331
|
+
_formatCcApiRoutesIndex,
|
|
7332
|
+
_formatCcCliCommandsIndex,
|
|
7333
|
+
_resetPreambleCache,
|
|
7272
7334
|
};
|
|
7273
7335
|
|
|
7274
7336
|
// Start the HTTP server only when run directly (node dashboard.js).
|
package/engine/cli.js
CHANGED
|
@@ -97,27 +97,41 @@ function handleCommand(cmd, args) {
|
|
|
97
97
|
} else {
|
|
98
98
|
console.log(`Unknown command: ${cmd}`);
|
|
99
99
|
console.log('Commands:');
|
|
100
|
-
|
|
101
|
-
console.log(' stop Stop engine');
|
|
102
|
-
console.log(' pause / resume Pause/resume dispatching');
|
|
103
|
-
console.log(' status Show engine + agent state + fleet config');
|
|
104
|
-
console.log(' queue Show dispatch queue');
|
|
105
|
-
console.log(' sources Show work source status');
|
|
106
|
-
console.log(' discover Dry-run work discovery');
|
|
107
|
-
console.log(' dispatch Force a dispatch cycle');
|
|
108
|
-
console.log(' spawn <a> <p> Manually spawn agent with prompt');
|
|
109
|
-
console.log(' work <title> [o] Add to work-items.json queue');
|
|
110
|
-
console.log(' plan <src> [p] Generate PRD from a plan (file or text)');
|
|
111
|
-
console.log(' kill Kill all active agents, reset to pending');
|
|
112
|
-
console.log(' complete <id> Mark a dispatch as done');
|
|
113
|
-
console.log(' cleanup Clean temp files, worktrees, zombies');
|
|
114
|
-
console.log(' mcp-sync Sync MCP servers from ~/.claude.json');
|
|
115
|
-
console.log(' doctor Check prerequisites and runtime health');
|
|
116
|
-
console.log(' config set-cli <R> [--model M] Persist defaultCli/defaultModel without starting');
|
|
100
|
+
for (const line of formatCliCommandHelpLines()) console.log(line);
|
|
117
101
|
process.exit(1);
|
|
118
102
|
}
|
|
119
103
|
}
|
|
120
104
|
|
|
105
|
+
// SoT for engine-CLI metadata: drives handleCommand's help text and the
|
|
106
|
+
// CC preamble's CLI index in dashboard.js. Drift-checked against `commands`.
|
|
107
|
+
const CLI_COMMAND_DOCS = Object.freeze({
|
|
108
|
+
start: { args: '[--cli R] [--model M]', summary: 'Start engine daemon (R = registered runtime)' },
|
|
109
|
+
stop: { args: '', summary: 'Stop engine' },
|
|
110
|
+
pause: { args: '', summary: 'Pause dispatching' },
|
|
111
|
+
resume: { args: '', summary: 'Resume dispatching' },
|
|
112
|
+
status: { args: '', summary: 'Show engine + agent state + fleet config' },
|
|
113
|
+
queue: { args: '', summary: 'Show dispatch queue' },
|
|
114
|
+
sources: { args: '', summary: 'Show work source status per project' },
|
|
115
|
+
discover: { args: '', summary: 'Dry-run work discovery' },
|
|
116
|
+
dispatch: { args: '', summary: 'Force a dispatch cycle' },
|
|
117
|
+
spawn: { args: '<agent> <prompt>', summary: 'Manually spawn an agent with prompt' },
|
|
118
|
+
work: { args: '<title> [opts]', summary: 'Add to work-items.json queue' },
|
|
119
|
+
plan: { args: '<file|text> [project]', summary: 'Generate PRD from a plan (file or text)' },
|
|
120
|
+
kill: { args: '', summary: 'Kill all active agents, reset to pending' },
|
|
121
|
+
complete: { args: '<dispatch-id>', summary: 'Mark a dispatch as done' },
|
|
122
|
+
cleanup: { args: '', summary: 'Clean temp files, worktrees, zombies' },
|
|
123
|
+
'mcp-sync': { args: '', summary: 'Sync MCP servers from ~/.claude.json' },
|
|
124
|
+
doctor: { args: '', summary: 'Check prerequisites and runtime health' },
|
|
125
|
+
config: { args: 'set-cli <R> [--model M]', summary: 'Persist defaultCli/defaultModel without starting' },
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
function formatCliCommandHelpLines() {
|
|
129
|
+
const entries = Object.entries(CLI_COMMAND_DOCS);
|
|
130
|
+
const lefts = entries.map(([name, { args }]) => ' ' + name + (args ? ' ' + args : ''));
|
|
131
|
+
const padTo = Math.max(...lefts.map(s => s.length)) + 2;
|
|
132
|
+
return entries.map(([, { summary }], i) => lefts[i].padEnd(padTo) + summary);
|
|
133
|
+
}
|
|
134
|
+
|
|
121
135
|
// ─── Runtime fleet flags (--cli / --model / --effort) ────────────────────────
|
|
122
136
|
//
|
|
123
137
|
// Shared by `start`, `restart`, and `config set-cli`. Single source of truth
|
|
@@ -1461,7 +1475,11 @@ const commands = {
|
|
|
1461
1475
|
|
|
1462
1476
|
module.exports = {
|
|
1463
1477
|
handleCommand,
|
|
1478
|
+
// exported for downstream indexing (dashboard CC preamble)
|
|
1479
|
+
CLI_COMMAND_DOCS,
|
|
1480
|
+
formatCliCommandHelpLines,
|
|
1464
1481
|
// exported for testing
|
|
1482
|
+
_listCommandKeys: () => Object.keys(commands),
|
|
1465
1483
|
_parseRuntimeFlags,
|
|
1466
1484
|
_modelLooksIncompatible,
|
|
1467
1485
|
_applyRuntimeFlags,
|
package/engine/meeting.js
CHANGED
|
@@ -730,6 +730,8 @@ function checkMeetingTimeouts(config) {
|
|
|
730
730
|
const meetings = getMeetings();
|
|
731
731
|
const timeout = (config.engine || {}).meetingRoundTimeout
|
|
732
732
|
|| ENGINE_DEFAULTS.meetingRoundTimeout;
|
|
733
|
+
const hardTimeout = (config.engine || {}).meetingRoundHardTimeout
|
|
734
|
+
|| ENGINE_DEFAULTS.meetingRoundHardTimeout;
|
|
733
735
|
|
|
734
736
|
for (const meeting of meetings) {
|
|
735
737
|
if (isTerminalMeetingStatus(meeting.status)) continue;
|
|
@@ -760,11 +762,34 @@ function checkMeetingTimeouts(config) {
|
|
|
760
762
|
meeting.transcript.push({ round: meeting.round, agent: 'system', type: 'timeout', content: `Round ${meeting.round} timed out after all participants finished`, at: ts() });
|
|
761
763
|
advanceMeetingIfRoundComplete(meeting, roundName, meeting.id, config);
|
|
762
764
|
saveMeeting(meeting);
|
|
765
|
+
} else if (elapsed >= hardTimeout) {
|
|
766
|
+
const failures = getRoundFailures(meeting, roundName, meeting.round, true);
|
|
767
|
+
const stalled = (meeting.participants || []).filter(p => !hasRoundTerminalOutcome(meeting, roundName, p, meeting.round));
|
|
768
|
+
const reason = `Hard meeting timeout after ${Math.round(elapsed / 60000)}min — agent did not produce ${roundName} output`;
|
|
769
|
+
for (const agentId of stalled) {
|
|
770
|
+
failures[agentId] = { reason, content: '', submittedAt: ts() };
|
|
771
|
+
meeting.transcript.push({ round: meeting.round, agent: agentId, type: 'failure', content: reason, at: ts() });
|
|
772
|
+
}
|
|
773
|
+
log('warn', `Meeting ${meeting.id}: round ${meeting.round} hit hard timeout after ${Math.round(elapsed / 60000)}min — marking ${stalled.length}/${totalCount} non-responders as failed and advancing`);
|
|
774
|
+
meeting.transcript.push({ round: meeting.round, agent: 'system', type: 'timeout', content: `Round ${meeting.round} hard timeout — ${stalled.length} non-responder(s) marked failed`, at: ts() });
|
|
775
|
+
advanceMeetingIfRoundComplete(meeting, roundName, meeting.id, config);
|
|
776
|
+
saveMeeting(meeting);
|
|
763
777
|
} else {
|
|
764
778
|
log('warn', `Meeting ${meeting.id}: round ${meeting.round} timed out after ${Math.round(elapsed / 60000)}min — waiting for all participants to finish (${respondedCount}/${totalCount} succeeded)`);
|
|
765
779
|
}
|
|
766
780
|
} else if (meeting.status === 'concluding') {
|
|
767
|
-
|
|
781
|
+
if (elapsed >= hardTimeout) {
|
|
782
|
+
const reason = `Hard meeting timeout after ${Math.round(elapsed / 60000)}min — conclusion agent did not produce output`;
|
|
783
|
+
const failures = getRoundFailures(meeting, 'conclude', meeting.round, true);
|
|
784
|
+
const conclusionAgent = (meeting.participants || []).find(p => !hasRoundTerminalOutcome(meeting, 'conclude', p, meeting.round)) || meeting.participants?.[0] || 'system';
|
|
785
|
+
failures[conclusionAgent] = { reason, content: '', submittedAt: ts() };
|
|
786
|
+
meeting.transcript.push({ round: meeting.round, agent: conclusionAgent, type: 'failure', content: reason, at: ts() });
|
|
787
|
+
log('warn', `Meeting ${meeting.id}: conclusion round hit hard timeout after ${Math.round(elapsed / 60000)}min — synthesising fallback conclusion`);
|
|
788
|
+
advanceMeetingIfRoundComplete(meeting, 'conclude', meeting.id, config);
|
|
789
|
+
saveMeeting(meeting);
|
|
790
|
+
} else {
|
|
791
|
+
log('warn', `Meeting ${meeting.id}: conclusion round timed out after ${Math.round(elapsed / 60000)}min — waiting for the conclusion agent to finish`);
|
|
792
|
+
}
|
|
768
793
|
}
|
|
769
794
|
}
|
|
770
795
|
}
|
package/engine/shared.js
CHANGED
|
@@ -861,7 +861,8 @@ const ENGINE_DEFAULTS = {
|
|
|
861
861
|
prNoOpFixPauseAttempts: 2, // pause one PR automation cause after repeated no-op fixes for unchanged evidence
|
|
862
862
|
completionReportRetentionDays: 90, // retain completion report sidecars beyond capped dispatch history
|
|
863
863
|
completionReportMaxFiles: 5000, // hard cap for completion report sidecars during cleanup
|
|
864
|
-
meetingRoundTimeout: 900000, // 15min per meeting round
|
|
864
|
+
meetingRoundTimeout: 900000, // 15min per meeting round — soft signal; logs a "still waiting" warning each tick
|
|
865
|
+
meetingRoundHardTimeout: 3600000, // 60min hard backstop — non-terminal participants are marked failed and the round advances. Prevents permanent stalls if an agent's dispatch never spawns or its completion gets dropped.
|
|
865
866
|
evalLoop: true, // enable review→fix loop after implementation completes
|
|
866
867
|
evalMaxIterations: 3, // legacy UI/config field; engine discovery no longer enforces review→fix cycle caps
|
|
867
868
|
evalMaxCost: null, // USD ceiling per work item across all eval iterations; null = no limit (gather baseline data first)
|
package/engine.js
CHANGED
|
@@ -4326,6 +4326,17 @@ async function tickInner() {
|
|
|
4326
4326
|
|
|
4327
4327
|
// Build set of agents currently active (one task per agent at a time).
|
|
4328
4328
|
const busyAgents = new Set((dispatch.active || []).map(d => d.agent));
|
|
4329
|
+
// W-motc4y1n000t1a5f: Track agents that already have a pending dispatch in
|
|
4330
|
+
// the queue. Reassignment routes (busy / unspawned-temp) must not move a
|
|
4331
|
+
// dispatch onto an agent who already has their own pending entry — order-
|
|
4332
|
+
// dependent iteration would otherwise double-book that agent. Seeded once
|
|
4333
|
+
// from the snapshot of pending and updated on successful reassignment.
|
|
4334
|
+
const pendingAgents = new Set();
|
|
4335
|
+
for (const p of (dispatch.pending || [])) {
|
|
4336
|
+
if (typeof p.agent === 'string' && p.agent && p.agent !== routing.ANY_AGENT) {
|
|
4337
|
+
pendingAgents.add(p.agent);
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4329
4340
|
// Branch mutex: track branches locked by active dispatches to prevent concurrent writes
|
|
4330
4341
|
const lockedBranches = new Set();
|
|
4331
4342
|
for (const d of (dispatch.active || [])) {
|
|
@@ -4409,9 +4420,12 @@ async function tickInner() {
|
|
|
4409
4420
|
const isUnspawnedTemp = item.agent?.startsWith('temp-') && !busyAgents.has(item.agent);
|
|
4410
4421
|
if (isUnspawnedTemp) {
|
|
4411
4422
|
const altAgent = resolvePendingDispatchAgent(item, config);
|
|
4412
|
-
|
|
4423
|
+
// W-motc4y1n000t1a5f: don't reassign onto an agent who already has
|
|
4424
|
+
// their own pending dispatch — that would double-book the alt.
|
|
4425
|
+
if (altAgent && altAgent !== item.agent && !pendingAgents.has(altAgent)) {
|
|
4413
4426
|
const prevAgent = item.agent;
|
|
4414
4427
|
assignPendingDispatchAgent(item, altAgent, config);
|
|
4428
|
+
pendingAgents.add(altAgent);
|
|
4415
4429
|
log('info', `Reassigning ${item.id} from unspawned temp ${prevAgent} to ${altAgent} — temp agent never spawned`);
|
|
4416
4430
|
// Persist reassignment to dispatch.json so it survives restarts/ticks
|
|
4417
4431
|
persistPendingDispatchAgent(item);
|
|
@@ -4427,10 +4441,14 @@ async function tickInner() {
|
|
|
4427
4441
|
continue; // Valid hard pin — keep waiting for pinned agent
|
|
4428
4442
|
}
|
|
4429
4443
|
// agent busy and idle alternative available — reroute immediately (no threshold)
|
|
4444
|
+
// W-motc4y1n000t1a5f: pendingAgents check prevents reassigning onto an
|
|
4445
|
+
// agent who already has their own pending dispatch (order-dependent
|
|
4446
|
+
// double-book in the meeting fan-out scenario).
|
|
4430
4447
|
const altAgent = resolvePendingDispatchAgent(item, config);
|
|
4431
|
-
if (altAgent && altAgent !== originalAgent && !busyAgents.has(altAgent)) {
|
|
4448
|
+
if (altAgent && altAgent !== originalAgent && !busyAgents.has(altAgent) && !pendingAgents.has(altAgent)) {
|
|
4432
4449
|
log('info', `Reassigning ${item.id} from ${originalAgent} to ${altAgent} — agent busy and idle alternative available`);
|
|
4433
4450
|
assignPendingDispatchAgent(item, altAgent, config);
|
|
4451
|
+
pendingAgents.add(altAgent);
|
|
4434
4452
|
persistPendingDispatchAgent(item);
|
|
4435
4453
|
// Fall through to branch mutex / concurrency checks below
|
|
4436
4454
|
} else if (isSoftFixDispatch(item)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1742",
|
|
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"
|
package/prompts/cc-system.md
CHANGED
|
@@ -30,30 +30,35 @@ CAN modify: notes, plans, knowledge, work items, pull-requests.json, routing.md,
|
|
|
30
30
|
Minions state lives in `{{minions_dir}}/`. Key paths: `config.json` (config), `routing.md` (dispatch rules), `projects/{name}/work-items.json` & `pull-requests.json` (per-project), `agents/{id}/` (charters, output), `plans/` & `prd/` (plans), `knowledge/` (KB), `notes/inbox/` (inbox), `engine/dispatch.json` (queue), `playbooks/` (templates). Use tools to read specifics.
|
|
31
31
|
|
|
32
32
|
## Role: Orchestrator
|
|
33
|
-
|
|
33
|
+
You are primarily a dispatcher. Agents have full Claude Code + worktrees + MCP tools and are better suited for real work — but you are not hard-stopped from handling small requests yourself.
|
|
34
34
|
|
|
35
|
-
###
|
|
35
|
+
### Step 1 — Estimate difficulty before responding
|
|
36
|
+
State the size in 3-4 words to yourself, then act:
|
|
37
|
+
- **Small** (≤3 tool calls, 1-2 files, no cross-module reasoning): you MAY do it yourself.
|
|
38
|
+
- **Medium** (4-10 tool calls, 3+ files, multi-file reasoning, real refactor): you MUST delegate.
|
|
39
|
+
- **Large** (10+ tool calls, cross-cutting, multi-stage): you MUST delegate, consider a plan with decomposition.
|
|
40
|
+
|
|
41
|
+
### Step 2 — Delegate when ≥ Medium (the hard stop)
|
|
42
|
+
Always delegate these to an agent — do not attempt them yourself even if they look small at first:
|
|
36
43
|
- Code changes, fixes, refactors, new features → `implement` or `fix`
|
|
37
44
|
- Exploration, investigation, research, audits → `explore`
|
|
38
45
|
- Code reviews → `review`
|
|
39
46
|
- Testing → `test`
|
|
40
47
|
- Architecture analysis → `explore`
|
|
41
|
-
-
|
|
48
|
+
- Anything ≥ Medium per Step 1
|
|
42
49
|
|
|
43
|
-
###
|
|
50
|
+
### Step 3 — Small tasks: do them yourself when it's faster than dispatching
|
|
51
|
+
Examples (not an exhaustive whitelist — apply Step 1 to anything not listed):
|
|
44
52
|
- Quick status lookups (reading 1-2 state files)
|
|
45
53
|
- Notes, plan edits, KB entries, routing updates
|
|
46
54
|
- Git ops the user explicitly asked CC to do
|
|
47
55
|
- Simple config changes (`set-config`)
|
|
48
56
|
- Answering questions from context you already have
|
|
57
|
+
- One-line edits to non-protected files when the change is unambiguous
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
Before responding, estimate the task size:
|
|
52
|
-
- **Small** (≤3 tool calls, 1-2 files): do it yourself
|
|
53
|
-
- **Medium** (4-10 tool calls, 3+ files): DELEGATE to an agent
|
|
54
|
-
- **Large** (10+ tool calls, cross-cutting): DELEGATE, consider a plan with decomposition
|
|
59
|
+
If you start a small task and discover it's actually Medium (3+ files, more tool calls than expected, surprising complexity), STOP and delegate instead of pushing through.
|
|
55
60
|
|
|
56
|
-
When in doubt
|
|
61
|
+
When genuinely in doubt about the size, delegate — agents have isolated worktrees, full tool access, and no turn limits.
|
|
57
62
|
|
|
58
63
|
## Actions
|
|
59
64
|
Append actions at the END of your response. Write your response first, then `===ACTIONS===` on its own line, then a JSON array. No text after the JSON. Omit entirely if no actions needed.
|
|
@@ -149,4 +154,13 @@ Terms like schedules, pipelines, agents, inbox, work items, plans, PRD, PRs, dis
|
|
|
149
154
|
1. Answer from the state preamble and context first. Only use tools for specific file lookups the user asked about — not to explore or investigate.
|
|
150
155
|
2. Be specific — cite IDs, names, filenames, line numbers.
|
|
151
156
|
3. Never modify engine source. Never push to git without user confirmation.
|
|
152
|
-
4.
|
|
157
|
+
4. Estimate first, then act (see Role: Orchestrator). For Medium-and-above tasks, your tools are for orientation; the agent does the work. For Small tasks, you may do them yourself.
|
|
158
|
+
|
|
159
|
+
## API & CLI Index (auto-injected)
|
|
160
|
+
Your state preamble (delivered alongside this prompt at session start) carries an auto-generated **API Index** rendered from `dashboard.js` `ROUTES` and a **CLI Index** rendered from `engine/cli.js` `CLI_COMMAND_DOCS`. Both are single-source-of-truth — adding a new HTTP endpoint or CLI command auto-surfaces it in your preamble; do not memorize the named action shorthand list above as exhaustive.
|
|
161
|
+
|
|
162
|
+
For any `/api/...` endpoint that doesn't have a matching named action above, emit the generic fallback shape:
|
|
163
|
+
`{"type":"<short-descriptor>","endpoint":"/api/...","params":{...}}`
|
|
164
|
+
The action runner accepts any local `/api/` path and POSTs `params` as JSON.
|
|
165
|
+
|
|
166
|
+
For CLI commands (`minions <cmd>`), use Bash to invoke them when delegating would be heavier than just running the command.
|