@yemi33/minions 0.1.1893 → 0.1.1895
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/engine/cli.js +36 -4
- package/engine/preflight.js +20 -20
- package/engine/shared.js +1 -1
- package/engine.js +0 -1
- package/package.json +1 -1
- package/playbooks/shared-rules.md +1 -1
package/engine/cli.js
CHANGED
|
@@ -1144,7 +1144,8 @@ const commands = {
|
|
|
1144
1144
|
const e = engine();
|
|
1145
1145
|
if (!title) {
|
|
1146
1146
|
console.log('Usage: node .minions/engine.js work "<title>" [options-json]');
|
|
1147
|
-
console.log('Options: {"type":"implement","priority":"high","agent":"dallas","description":"...","branch":"feature/..."}');
|
|
1147
|
+
console.log('Options: {"id":"W-customid","type":"implement","priority":"high","agent":"dallas","description":"...","branch":"feature/...","project":"minions"}');
|
|
1148
|
+
console.log(' id Optional caller-supplied work item ID. Defaults to a cuid-style W-<id>.');
|
|
1148
1149
|
return;
|
|
1149
1150
|
}
|
|
1150
1151
|
|
|
@@ -1157,7 +1158,7 @@ const commands = {
|
|
|
1157
1158
|
}
|
|
1158
1159
|
|
|
1159
1160
|
const config = getConfig();
|
|
1160
|
-
const { getProjects, projectWorkItemsPath, resolveProjectSource } = require('./shared');
|
|
1161
|
+
const { getProjects, projectWorkItemsPath, resolveProjectSource, uid, safeJsonArr } = require('./shared');
|
|
1161
1162
|
const projects = getProjects(config);
|
|
1162
1163
|
const target = opts.project ? resolveProjectSource(opts.project, projects, { allowCentral: false }) : null;
|
|
1163
1164
|
if (target?.error) {
|
|
@@ -1166,10 +1167,36 @@ const commands = {
|
|
|
1166
1167
|
}
|
|
1167
1168
|
const targetProject = target?.project || (projects.length > 0 ? projects[0] : null);
|
|
1168
1169
|
const wiPath = projectWorkItemsPath(targetProject);
|
|
1170
|
+
const archivePath = wiPath.replace(/\.json$/, '-archive.json');
|
|
1171
|
+
|
|
1172
|
+
// Caller-supplied id: validate and pre-check live + archive for collisions
|
|
1173
|
+
// BEFORE acquiring the work-items lock, so a rejection never mutates state.
|
|
1174
|
+
let requestedId = null;
|
|
1175
|
+
if (opts.id != null) {
|
|
1176
|
+
if (typeof opts.id !== 'string' || !opts.id.trim()) {
|
|
1177
|
+
console.log('Error: opts.id must be a non-empty string');
|
|
1178
|
+
process.exit(1);
|
|
1179
|
+
}
|
|
1180
|
+
requestedId = opts.id.trim();
|
|
1181
|
+
const liveItems = safeJsonArr(wiPath);
|
|
1182
|
+
const archivedItems = safeJsonArr(archivePath);
|
|
1183
|
+
if (liveItems.some(w => w?.id === requestedId) || archivedItems.some(w => w?.id === requestedId)) {
|
|
1184
|
+
console.log(`Error: work item id "${requestedId}" already exists in ${path.basename(wiPath)} or its archive`);
|
|
1185
|
+
process.exit(1);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1169
1189
|
let item;
|
|
1190
|
+
let collision = false;
|
|
1170
1191
|
mutateWorkItems(wiPath, items => {
|
|
1192
|
+
const id = requestedId || ('W-' + uid());
|
|
1193
|
+
// Re-check inside the lock to close the TOCTOU race against other writers.
|
|
1194
|
+
if (items.some(w => w?.id === id)) {
|
|
1195
|
+
collision = true;
|
|
1196
|
+
return items;
|
|
1197
|
+
}
|
|
1171
1198
|
item = {
|
|
1172
|
-
id
|
|
1199
|
+
id,
|
|
1173
1200
|
title: title,
|
|
1174
1201
|
type: opts.type || 'implement',
|
|
1175
1202
|
status: WI_STATUS.QUEUED,
|
|
@@ -1184,7 +1211,12 @@ const commands = {
|
|
|
1184
1211
|
items.push(item);
|
|
1185
1212
|
});
|
|
1186
1213
|
|
|
1187
|
-
|
|
1214
|
+
if (collision || !item) {
|
|
1215
|
+
console.log(`Error: work item id collision detected for "${requestedId || 'auto-generated'}"`);
|
|
1216
|
+
process.exit(1);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
console.log(`Queued work item: ${item.id} — ${item.title} (project: ${targetProject?.name || 'default'})`);
|
|
1188
1220
|
console.log(` Type: ${item.type} | Priority: ${item.priority} | Agent: ${item.agent || 'auto'}`);
|
|
1189
1221
|
},
|
|
1190
1222
|
|
package/engine/preflight.js
CHANGED
|
@@ -123,7 +123,7 @@ function _checkRuntimeBinary(runtimeName, { optional = false } = {}) {
|
|
|
123
123
|
return {
|
|
124
124
|
name: `Runtime: ${runtimeName}`,
|
|
125
125
|
ok: false,
|
|
126
|
-
message: `unknown runtime — ${e.message}`,
|
|
126
|
+
message: `unknown runtime — ${e.message} (see docs/copilot-cli-schema.md)`,
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
let resolved = null;
|
|
@@ -146,8 +146,8 @@ function _checkRuntimeBinary(runtimeName, { optional = false } = {}) {
|
|
|
146
146
|
name: `Runtime: ${runtimeName}`,
|
|
147
147
|
ok: optional ? 'warn' : false,
|
|
148
148
|
message: optional
|
|
149
|
-
? `not installed (optional) — ${hint}`
|
|
150
|
-
: `not found — ${hint}`,
|
|
149
|
+
? `not installed (optional) — ${hint} (see docs/copilot-cli-schema.md)`
|
|
150
|
+
: `not found — ${hint} (see docs/copilot-cli-schema.md)`,
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -400,11 +400,11 @@ async function _modelDiscoveryResults(config) {
|
|
|
400
400
|
catch { continue; /* unknown-cli warning was already emitted by runtimeConfigWarnings */ }
|
|
401
401
|
|
|
402
402
|
if (fleetDisabled) {
|
|
403
|
-
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: 'discovery disabled (engine.disableModelDiscovery)' });
|
|
403
|
+
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: 'discovery disabled (engine.disableModelDiscovery) — see docs/copilot-cli-schema.md' });
|
|
404
404
|
continue;
|
|
405
405
|
}
|
|
406
406
|
if (!adapter.capabilities || adapter.capabilities.modelDiscovery !== true) {
|
|
407
|
-
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: 'discovery unavailable (no enumeration mechanism)' });
|
|
407
|
+
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: 'discovery unavailable (no enumeration mechanism) — see docs/copilot-cli-schema.md' });
|
|
408
408
|
continue;
|
|
409
409
|
}
|
|
410
410
|
try {
|
|
@@ -412,10 +412,10 @@ async function _modelDiscoveryResults(config) {
|
|
|
412
412
|
if (Array.isArray(out.models) && out.models.length > 0) {
|
|
413
413
|
results.push({ name: `Models: ${runtimeName}`, ok: true, message: `${out.models.length} models cached` });
|
|
414
414
|
} else {
|
|
415
|
-
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: 'discovery unavailable (API returned no models — check token)' });
|
|
415
|
+
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: 'discovery unavailable (API returned no models — check token) — see docs/copilot-cli-schema.md' });
|
|
416
416
|
}
|
|
417
417
|
} catch (e) {
|
|
418
|
-
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: `discovery error — ${e && e.message ? e.message : 'unknown'}` });
|
|
418
|
+
results.push({ name: `Models: ${runtimeName}`, ok: 'warn', message: `discovery error — ${e && e.message ? e.message : 'unknown'} (see docs/copilot-cli-schema.md)` });
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
return results;
|
|
@@ -442,7 +442,7 @@ function doctor(minionsHome) {
|
|
|
442
442
|
if (fs.existsSync(engineJs)) {
|
|
443
443
|
runtimeResults.push({ name: 'Minions installed', ok: true, message: minionsHome });
|
|
444
444
|
} else {
|
|
445
|
-
runtimeResults.push({ name: 'Minions installed', ok: false, message: `not found at ${minionsHome} — run: minions init` });
|
|
445
|
+
runtimeResults.push({ name: 'Minions installed', ok: false, message: `not found at ${minionsHome} — run: minions init (see docs/distribution.md)` });
|
|
446
446
|
}
|
|
447
447
|
|
|
448
448
|
// Check config.json
|
|
@@ -454,13 +454,13 @@ function doctor(minionsHome) {
|
|
|
454
454
|
if (real.length > 0) {
|
|
455
455
|
runtimeResults.push({ name: 'Projects configured', ok: true, message: `${real.length} project(s)` });
|
|
456
456
|
} else {
|
|
457
|
-
runtimeResults.push({ name: 'Projects configured', ok: false, message: 'no projects — run: minions add <dir>' });
|
|
457
|
+
runtimeResults.push({ name: 'Projects configured', ok: false, message: 'no projects — run: minions add <dir> (see docs/auto-discovery.md)' });
|
|
458
458
|
}
|
|
459
459
|
|
|
460
460
|
// Check project paths exist
|
|
461
461
|
for (const p of real) {
|
|
462
462
|
if (p.localPath && !fs.existsSync(p.localPath)) {
|
|
463
|
-
runtimeResults.push({ name: `Project "${p.name}"`, ok: false, message: `path not found: ${p.localPath}` });
|
|
463
|
+
runtimeResults.push({ name: `Project "${p.name}"`, ok: false, message: `path not found: ${p.localPath} — fix config.json or re-run: minions add <dir> (see docs/auto-discovery.md)` });
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
466
|
|
|
@@ -469,7 +469,7 @@ function doctor(minionsHome) {
|
|
|
469
469
|
if (Object.keys(agents).length > 0) {
|
|
470
470
|
runtimeResults.push({ name: 'Agents configured', ok: true, message: `${Object.keys(agents).length} agent(s)` });
|
|
471
471
|
} else {
|
|
472
|
-
runtimeResults.push({ name: 'Agents configured', ok: false, message: 'no agents in config.json' });
|
|
472
|
+
runtimeResults.push({ name: 'Agents configured', ok: false, message: 'no agents in config.json — re-run: minions init (see docs/auto-discovery.md)' });
|
|
473
473
|
}
|
|
474
474
|
|
|
475
475
|
// Check Teams integration — supports client secret OR certificate auth
|
|
@@ -482,7 +482,7 @@ function doctor(minionsHome) {
|
|
|
482
482
|
!teams.appId && 'appId',
|
|
483
483
|
!teams.appPassword && !teams.certPath && 'appPassword or certPath+privateKeyPath+tenantId',
|
|
484
484
|
].filter(Boolean).join(', ');
|
|
485
|
-
runtimeResults.push({ name: 'Teams integration', ok: 'warn', message: `enabled but missing: ${missing}` });
|
|
485
|
+
runtimeResults.push({ name: 'Teams integration', ok: 'warn', message: `enabled but missing: ${missing} — see docs/teams-setup.md` });
|
|
486
486
|
} else {
|
|
487
487
|
const authMode = hasCert ? 'certificate' : 'client secret';
|
|
488
488
|
runtimeResults.push({ name: 'Teams integration', ok: true, message: `configured (${authMode})` });
|
|
@@ -491,7 +491,7 @@ function doctor(minionsHome) {
|
|
|
491
491
|
runtimeResults.push({ name: 'Teams integration', ok: 'warn', message: 'disabled — see docs/teams-setup.md' });
|
|
492
492
|
}
|
|
493
493
|
} catch {
|
|
494
|
-
runtimeResults.push({ name: 'Config', ok: false, message: `missing or invalid — run: minions init` });
|
|
494
|
+
runtimeResults.push({ name: 'Config', ok: false, message: `missing or invalid — run: minions init (see docs/distribution.md)` });
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
// Check engine status
|
|
@@ -509,12 +509,12 @@ function doctor(minionsHome) {
|
|
|
509
509
|
alive = true;
|
|
510
510
|
}
|
|
511
511
|
} catch { /* process may be dead */ }
|
|
512
|
-
runtimeResults.push({ name: 'Engine', ok: alive, message: alive ? `running (PID ${control.pid})` : `stale PID ${control.pid} — run: minions start` });
|
|
512
|
+
runtimeResults.push({ name: 'Engine', ok: alive, message: alive ? `running (PID ${control.pid})` : `stale PID ${control.pid} — run: minions start (see docs/engine-restart.md)` });
|
|
513
513
|
} else {
|
|
514
|
-
runtimeResults.push({ name: 'Engine', ok: 'warn', message: `${control.state || 'stopped'} — run: minions start` });
|
|
514
|
+
runtimeResults.push({ name: 'Engine', ok: 'warn', message: `${control.state || 'stopped'} — run: minions start (see docs/engine-restart.md)` });
|
|
515
515
|
}
|
|
516
516
|
} catch {
|
|
517
|
-
runtimeResults.push({ name: 'Engine', ok: 'warn', message: 'not started — run: minions start' });
|
|
517
|
+
runtimeResults.push({ name: 'Engine', ok: 'warn', message: 'not started — run: minions start (see docs/engine-restart.md)' });
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
// Check dashboard (try HTTP)
|
|
@@ -523,8 +523,8 @@ function doctor(minionsHome) {
|
|
|
523
523
|
const req = http.get('http://localhost:7331/api/health', { timeout: 2000 }, res => {
|
|
524
524
|
resolve({ name: 'Dashboard', ok: true, message: 'running on http://localhost:7331' });
|
|
525
525
|
});
|
|
526
|
-
req.on('error', () => resolve({ name: 'Dashboard', ok: 'warn', message: 'not reachable on :7331 — run: minions dash' }));
|
|
527
|
-
req.on('timeout', () => { req.destroy(); resolve({ name: 'Dashboard', ok: 'warn', message: 'not reachable on :7331 — run: minions dash' }); });
|
|
526
|
+
req.on('error', () => resolve({ name: 'Dashboard', ok: 'warn', message: 'not reachable on :7331 — run: minions dash (see docs/engine-restart.md)' }));
|
|
527
|
+
req.on('timeout', () => { req.destroy(); resolve({ name: 'Dashboard', ok: 'warn', message: 'not reachable on :7331 — run: minions dash (see docs/engine-restart.md)' }); });
|
|
528
528
|
});
|
|
529
529
|
|
|
530
530
|
return dashCheck.then(async dashResult => {
|
|
@@ -537,12 +537,12 @@ function doctor(minionsHome) {
|
|
|
537
537
|
if (playbooks.length > 0) {
|
|
538
538
|
runtimeResults.push({ name: 'Playbooks', ok: true, message: `${playbooks.length} playbooks found` });
|
|
539
539
|
} else {
|
|
540
|
-
runtimeResults.push({ name: 'Playbooks', ok: false, message: 'no playbooks found in playbooks/ — run: minions init --force' });
|
|
540
|
+
runtimeResults.push({ name: 'Playbooks', ok: false, message: 'no playbooks found in playbooks/ — run: minions init --force (see docs/distribution.md)' });
|
|
541
541
|
}
|
|
542
542
|
|
|
543
543
|
// Check port 7331 availability (only if dashboard isn't running)
|
|
544
544
|
if (dashResult.ok !== true) {
|
|
545
|
-
runtimeResults.push({ name: 'Port 7331', ok: 'warn', message: 'dashboard not running — port status unknown' });
|
|
545
|
+
runtimeResults.push({ name: 'Port 7331', ok: 'warn', message: 'dashboard not running — port status unknown (see docs/engine-restart.md)' });
|
|
546
546
|
}
|
|
547
547
|
|
|
548
548
|
// Fleet defaults + per-runtime model discovery (P-9e8a3f1d). Both depend
|
package/engine/shared.js
CHANGED
|
@@ -1716,7 +1716,7 @@ const ESCALATION_POLICY = {
|
|
|
1716
1716
|
};
|
|
1717
1717
|
|
|
1718
1718
|
// Structured completion protocol — fields agents must produce in ```completion blocks
|
|
1719
|
-
const COMPLETION_FIELDS = ['status', 'summary', 'files_changed', 'tests', 'pr', '
|
|
1719
|
+
const COMPLETION_FIELDS = ['status', 'summary', 'files_changed', 'tests', 'pr', 'not_changed', 'failure_class', 'retryable', 'needs_rerun', 'verdict', 'artifacts'];
|
|
1720
1720
|
|
|
1721
1721
|
const DEFAULT_AGENT_METRICS = {
|
|
1722
1722
|
tasksCompleted: 0, tasksErrored: 0,
|
package/engine.js
CHANGED
|
@@ -1649,7 +1649,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1649
1649
|
errorReason = structuredCompletion
|
|
1650
1650
|
? String(
|
|
1651
1651
|
structuredCompletion.summary
|
|
1652
|
-
|| structuredCompletion.pending
|
|
1653
1652
|
|| structuredCompletion.failure_class
|
|
1654
1653
|
|| `Agent reported ${structuredCompletion.status || 'failure'}`
|
|
1655
1654
|
).slice(0, 300)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1895",
|
|
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"
|
|
@@ -67,7 +67,7 @@ Bias toward senior-engineer restraint:
|
|
|
67
67
|
The engine provides a completion report path in the prompt and in `MINIONS_COMPLETION_REPORT`. Before exiting, write JSON there with the actual outcome:
|
|
68
68
|
|
|
69
69
|
```json
|
|
70
|
-
{"status":"success","summary":"what changed and how it was validated","verdict":null,"pr":"PR id/url or N/A","failure_class":"N/A","retryable":false,"needs_rerun":false,"artifacts":[{"type":"note|plan|prd|pr|file","path":"relative/path/or/url","title":"short label"}]}
|
|
70
|
+
{"status":"success","summary":"what changed and how it was validated","verdict":null,"pr":"PR id/url or N/A","failure_class":"N/A","retryable":false,"needs_rerun":false,"not_changed":"adjacent X left alone; refactor Y declined as out of scope","artifacts":[{"type":"note|plan|prd|pr|file","path":"relative/path/or/url","title":"short label"}]}
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
For the canonical schema — every field, the `failure_class` enum, `noop:true` semantics, `retryable` / `needs_rerun` shape, and the artifacts array — see `docs/completion-reports.md`. The JSON report is the primary signal; fenced `completion` blocks in stdout are accepted only as a fallback.
|