@yemi33/minions 0.1.2369 → 0.1.2371
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/bin/minions.js +38 -11
- package/dashboard/js/memory-search.js +112 -0
- package/dashboard/js/render-kb.js +15 -0
- package/dashboard/js/render-other.js +2 -30
- package/dashboard/js/render-work-items.js +0 -34
- package/dashboard/js/settings.js +27 -27
- package/dashboard/pages/inbox.html +1 -1
- package/dashboard/pages/tools.html +1 -1
- package/dashboard.js +148 -258
- package/docs/README.md +2 -3
- package/docs/architecture.excalidraw +2 -2
- package/docs/auto-discovery.md +3 -3
- package/docs/completion-reports.md +0 -121
- package/docs/copilot-cli-schema.md +9 -17
- package/docs/deprecated.json +0 -51
- package/docs/design-state-storage.md +4 -4
- package/docs/harness-propagation.md +33 -263
- package/docs/human-vs-automated.md +1 -1
- package/docs/named-agents.md +0 -2
- package/docs/plan-lifecycle.md +5 -6
- package/docs/qa-runbook-lifecycle.md +10 -25
- package/docs/shared-lifecycle-module-map.md +2 -10
- package/docs/team-memory.md +18 -4
- package/engine/ado-comment.js +5 -11
- package/engine/ado.js +10 -5
- package/engine/cleanup.js +16 -36
- package/engine/cli.js +13 -175
- package/engine/comment-format.js +8 -182
- package/engine/consolidation.js +72 -1
- package/engine/db/index.js +60 -10
- package/engine/db/migrations/017-agent-memory.js +208 -0
- package/engine/db/migrations/018-sql-only-cutover.js +56 -0
- package/engine/dispatch-store.js +0 -114
- package/engine/dispatch.js +1 -6
- package/engine/features.js +6 -0
- package/engine/gh-comment.js +2 -10
- package/engine/github.js +8 -6
- package/engine/lifecycle.js +141 -173
- package/engine/llm.js +9 -11
- package/engine/managed-spawn.js +1 -6
- package/engine/memory-retrieval.js +165 -0
- package/engine/memory-store.js +367 -0
- package/engine/metrics-store.js +4 -128
- package/engine/pipeline.js +4 -7
- package/engine/playbook.js +64 -198
- package/engine/prd-store.js +115 -141
- package/engine/preflight.js +8 -55
- package/engine/projects.js +34 -41
- package/engine/pull-requests-store.js +9 -234
- package/engine/qa-runs.js +4 -15
- package/engine/qa-sessions.js +5 -17
- package/engine/queries.js +23 -103
- package/engine/routing.js +1 -1
- package/engine/runtimes/claude.js +1 -2
- package/engine/runtimes/codex.js +0 -2
- package/engine/runtimes/copilot.js +1 -4
- package/engine/shared-branch-pr-reconcile.js +2 -5
- package/engine/shared.js +179 -533
- package/engine/small-state-store.js +12 -647
- package/engine/spawn-agent.js +5 -96
- package/engine/state-operations.js +166 -0
- package/engine/supervisor.js +0 -1
- package/engine/watch-actions.js +2 -3
- package/engine/watches-store.js +2 -128
- package/engine/work-items-store.js +3 -254
- package/engine.js +102 -334
- package/package.json +2 -2
- package/playbooks/build-fix-complex.md +0 -4
- package/playbooks/fix.md +0 -4
- package/playbooks/implement-shared.md +0 -4
- package/playbooks/implement.md +0 -4
- package/playbooks/plan-to-prd.md +16 -11
- package/playbooks/plan.md +0 -4
- package/playbooks/review.md +0 -6
- package/playbooks/shared-rules.md +0 -65
- package/docs/harness-transparency.md +0 -199
- package/docs/project-skills.md +0 -193
- package/engine/discover-project-skills.js +0 -673
- package/engine/playbook-intents.js +0 -76
package/engine/ado-comment.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* engine/ado-comment.js — Azure DevOps mirror of engine/gh-comment.js.
|
|
3
3
|
*
|
|
4
4
|
* Posts a minions PR-comment thread to ADO with the same hidden marker, the
|
|
5
|
-
* same
|
|
6
|
-
* link as the GitHub path — because all three are produced by the ONE neutral
|
|
5
|
+
* same deterministic brand link as the GitHub path — because both are produced by the ONE neutral
|
|
7
6
|
* builder `engine/comment-format.js#buildMinionsCommentBody`. This module owns
|
|
8
7
|
* only the ADO transport (REST `…/threads` POST) and ADO-specific input
|
|
9
8
|
* validation (orgBase / project / repositoryId / prNumber).
|
|
@@ -13,7 +12,7 @@
|
|
|
13
12
|
* unlinked on ADO (the GitHub backstop in buildMinionsCommentBody never ran).
|
|
14
13
|
* Routing ADO comments through this poster gives ADO the same guarantees as
|
|
15
14
|
* GitHub: marker present (so pollers classify the comment as agent-authored),
|
|
16
|
-
*
|
|
15
|
+
* brand trailer hyperlinked.
|
|
17
16
|
*
|
|
18
17
|
* Auth: a bearer token from `az account get-access-token` (via
|
|
19
18
|
* engine/ado-token.js#acquireAdoToken), threaded as `Authorization: Bearer`.
|
|
@@ -34,7 +33,7 @@
|
|
|
34
33
|
* changes) stay `active` so they block/notify the author.
|
|
35
34
|
*/
|
|
36
35
|
|
|
37
|
-
const { buildMinionsCommentBody
|
|
36
|
+
const { buildMinionsCommentBody } = require('./comment-format');
|
|
38
37
|
const { acquireAdoToken } = require('./ado-token');
|
|
39
38
|
|
|
40
39
|
const ADO_API_VERSION = '7.1';
|
|
@@ -95,7 +94,7 @@ async function _defaultAcquireToken() {
|
|
|
95
94
|
/**
|
|
96
95
|
* Post a minions PR comment to an Azure DevOps pull request.
|
|
97
96
|
*
|
|
98
|
-
* Mirrors engine/gh-comment.js#postPrComment: builds the marked +
|
|
97
|
+
* Mirrors engine/gh-comment.js#postPrComment: builds the marked +
|
|
99
98
|
* brand-linked body via the shared builder, then POSTs a new active thread.
|
|
100
99
|
*
|
|
101
100
|
* @param {object} args
|
|
@@ -107,8 +106,6 @@ async function _defaultAcquireToken() {
|
|
|
107
106
|
* @param {string} args.agentId minions agent id (marker)
|
|
108
107
|
* @param {string} args.kind comment kind (marker)
|
|
109
108
|
* @param {string} [args.workItemId] originating work-item id (marker)
|
|
110
|
-
* @param {object} [args.harnessUsed] grounded harnessUsed record (folded into body)
|
|
111
|
-
* @param {object} [args.skillSkipped] skipped-project-skill record `{name, reason}` (folded into body, visible)
|
|
112
109
|
* @param {number} [args.timeoutMs=30000]
|
|
113
110
|
* @param {Function} [args.acquireToken] () => Promise<string> — injectable token source
|
|
114
111
|
* @param {Function} [args.fetchImpl=fetch] injectable fetch
|
|
@@ -123,8 +120,6 @@ async function postAdoPrComment({
|
|
|
123
120
|
agentId,
|
|
124
121
|
kind,
|
|
125
122
|
workItemId,
|
|
126
|
-
harnessUsed,
|
|
127
|
-
skillSkipped,
|
|
128
123
|
resolved = false,
|
|
129
124
|
timeoutMs = 30000,
|
|
130
125
|
acquireToken = _defaultAcquireToken,
|
|
@@ -136,7 +131,7 @@ async function postAdoPrComment({
|
|
|
136
131
|
_validatePrNumber(prNumber);
|
|
137
132
|
|
|
138
133
|
// buildMinionsCommentBody validates marker fields and throws on bad input.
|
|
139
|
-
const finalBody = buildMinionsCommentBody({ agentId, kind, workItemId, body
|
|
134
|
+
const finalBody = buildMinionsCommentBody({ agentId, kind, workItemId, body });
|
|
140
135
|
|
|
141
136
|
const token = await acquireToken();
|
|
142
137
|
if (!token || typeof token !== 'string') {
|
|
@@ -186,7 +181,6 @@ module.exports = {
|
|
|
186
181
|
// Re-export the neutral builder so ADO callers have a single import surface,
|
|
187
182
|
// mirroring engine/gh-comment.js.
|
|
188
183
|
buildMinionsCommentBody,
|
|
189
|
-
buildSkippedSkillSection,
|
|
190
184
|
// Internal validators exported for tests.
|
|
191
185
|
_validateOrgBase,
|
|
192
186
|
_validateProject,
|
package/engine/ado.js
CHANGED
|
@@ -409,11 +409,13 @@ function applyAdoPrMetadata(pr, prData) {
|
|
|
409
409
|
updated = true;
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
-
// W-mpej044m00076d63:
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
|
|
412
|
+
// W-mpej044m00076d63 / W-mrezh0yb0007f733: keep `pr.created` aligned with
|
|
413
|
+
// ADO's real creationDate. The platform is authoritative for when a PR was
|
|
414
|
+
// opened, so adopt its value whenever the stored one is missing, a legacy
|
|
415
|
+
// date-only stamp, or a link/attach-time `now()` default (the bug where
|
|
416
|
+
// manually-linked PRs showed a "created today" date). `shouldAdoptPlatformCreated`
|
|
417
|
+
// compares instants so equivalent representations don't churn. Idempotent.
|
|
418
|
+
if (shared.shouldAdoptPlatformCreated(pr.created, prData.creationDate)) {
|
|
417
419
|
pr.created = prData.creationDate;
|
|
418
420
|
updated = true;
|
|
419
421
|
}
|
|
@@ -2606,6 +2608,9 @@ async function fetchAdoPrMetadata(prNum, adoOrg, adoProj, adoRepo, project) {
|
|
|
2606
2608
|
description: pr.description || '',
|
|
2607
2609
|
branch: stripRefsHeads(pr.sourceRefName),
|
|
2608
2610
|
author: pr.createdBy?.displayName || '',
|
|
2611
|
+
// W-mrezh0yb0007f733 — surface ADO's real creationDate so manual-link paths
|
|
2612
|
+
// can seed `pr.created` with the true value instead of link-time now().
|
|
2613
|
+
created: pr.creationDate || '',
|
|
2609
2614
|
};
|
|
2610
2615
|
}
|
|
2611
2616
|
|
package/engine/cleanup.js
CHANGED
|
@@ -1388,23 +1388,13 @@ async function runCleanup(config, verbose = false) {
|
|
|
1388
1388
|
}
|
|
1389
1389
|
// PRD items (missing_features[].status)
|
|
1390
1390
|
try {
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
prdDirEntries = fs.readdirSync(PRD_DIR);
|
|
1394
|
-
} catch (e) {
|
|
1395
|
-
log('warn', `migrate PRD statuses: failed to read ${PRD_DIR} — ${e.message}`);
|
|
1396
|
-
prdDirEntries = [];
|
|
1397
|
-
}
|
|
1398
|
-
const prdFiles = prdDirEntries.filter(f => f.endsWith('.json'));
|
|
1391
|
+
const prdStore = require('./prd-store');
|
|
1392
|
+
const prdFiles = prdStore.listPrdRows().filter(row => !row.archived).map(row => row.filename);
|
|
1399
1393
|
for (const pf of prdFiles) {
|
|
1400
1394
|
const prdPath = path.join(PRD_DIR, pf);
|
|
1395
|
+
const prd = prdStore.readPrd(prdPath);
|
|
1401
1396
|
let migrated = 0;
|
|
1402
|
-
|
|
1403
|
-
// safeJsonNoRestore: PRDs are terminal artifacts. If the active PRD
|
|
1404
|
-
// was archived but a stale .backup sidecar remains, never resurrect
|
|
1405
|
-
// it during a routine migration sweep (W-mouptdh1000h9f39).
|
|
1406
|
-
const prd = safeJsonNoRestore(prdPath);
|
|
1407
|
-
if (!prd?.missing_features) return;
|
|
1397
|
+
if (prd?.missing_features) {
|
|
1408
1398
|
for (const feat of prd.missing_features) {
|
|
1409
1399
|
if (LEGACY_DONE_ALIASES.has(feat.status)) {
|
|
1410
1400
|
feat.status = shared.WI_STATUS.DONE;
|
|
@@ -1414,8 +1404,8 @@ async function runCleanup(config, verbose = false) {
|
|
|
1414
1404
|
migrated++;
|
|
1415
1405
|
}
|
|
1416
1406
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1407
|
+
}
|
|
1408
|
+
if (migrated > 0) prdStore.writePrd(prdPath, prd);
|
|
1419
1409
|
if (migrated > 0) {
|
|
1420
1410
|
log('info', `Migrated ${migrated} legacy PRD item status(es) in ${pf}`);
|
|
1421
1411
|
}
|
|
@@ -1425,36 +1415,27 @@ async function runCleanup(config, verbose = false) {
|
|
|
1425
1415
|
// Reset orphaned PRD item statuses — dispatched/failed with no matching work item (#779)
|
|
1426
1416
|
cleaned.orphanedPrdStatuses = 0;
|
|
1427
1417
|
try {
|
|
1428
|
-
const wiIds = new Set(
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
for (const wi of items) { if (wi?.id) wiIds.add(wi.id); }
|
|
1432
|
-
}
|
|
1433
|
-
try {
|
|
1434
|
-
const centralWi = safeJsonArr(path.join(MINIONS_DIR, 'work-items.json'));
|
|
1435
|
-
for (const wi of centralWi) { if (wi?.id) wiIds.add(wi.id); }
|
|
1436
|
-
} catch { /* optional */ }
|
|
1418
|
+
const wiIds = new Set(
|
|
1419
|
+
queries.getWorkItems(config, { enrich: false }).map(wi => wi?.id).filter(Boolean)
|
|
1420
|
+
);
|
|
1437
1421
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
catch { orphanPrdEntries = []; }
|
|
1422
|
+
const prdStore = require('./prd-store');
|
|
1423
|
+
const orphanPrdEntries = prdStore.listPrdRows().filter(row => !row.archived).map(row => row.filename);
|
|
1441
1424
|
for (const pf of orphanPrdEntries) {
|
|
1442
1425
|
const prdPath = path.join(PRD_DIR, pf);
|
|
1443
|
-
|
|
1444
|
-
// from a stale .backup sidecar (W-mouptdh1000h9f39).
|
|
1445
|
-
const peek = safeJsonNoRestore(prdPath);
|
|
1426
|
+
const peek = prdStore.readPrd(prdPath);
|
|
1446
1427
|
if (!peek?.missing_features) continue;
|
|
1447
1428
|
let reset = 0;
|
|
1448
|
-
|
|
1449
|
-
|
|
1429
|
+
const prd = peek;
|
|
1430
|
+
if (prd?.missing_features) {
|
|
1450
1431
|
for (const feat of prd.missing_features) {
|
|
1451
1432
|
if ((feat.status === shared.WI_STATUS.DISPATCHED || feat.status === shared.WI_STATUS.FAILED) && !wiIds.has(feat.id)) {
|
|
1452
1433
|
feat.status = shared.WI_STATUS.PENDING;
|
|
1453
1434
|
reset++;
|
|
1454
1435
|
}
|
|
1455
1436
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1437
|
+
}
|
|
1438
|
+
if (reset > 0) prdStore.writePrd(prdPath, prd);
|
|
1458
1439
|
if (reset > 0) {
|
|
1459
1440
|
log('info', `Reset ${reset} orphaned PRD item status(es) → pending in ${pf}`);
|
|
1460
1441
|
cleaned.orphanedPrdStatuses += reset;
|
|
@@ -1669,7 +1650,6 @@ async function runCleanup(config, verbose = false) {
|
|
|
1669
1650
|
* that were written before that guard existed. */
|
|
1670
1651
|
function scrubStaleMetrics() {
|
|
1671
1652
|
const metricsPath = path.join(ENGINE_DIR, 'metrics.json');
|
|
1672
|
-
if (!fs.existsSync(metricsPath)) return;
|
|
1673
1653
|
mutateJsonFileLocked(metricsPath, metrics => {
|
|
1674
1654
|
for (const key of Object.keys(metrics)) {
|
|
1675
1655
|
if (key.startsWith('temp-') || key === 'agent1' || key.startsWith('_test')) {
|
package/engine/cli.js
CHANGED
|
@@ -247,10 +247,10 @@ const CLI_COMMAND_DOCS = Object.freeze({
|
|
|
247
247
|
kill: { args: '', summary: 'Kill all active agents, reset to pending' },
|
|
248
248
|
complete: { args: '<dispatch-id>', summary: 'Mark a dispatch as done' },
|
|
249
249
|
cleanup: { args: '', summary: 'Clean temp files, worktrees, zombies' },
|
|
250
|
-
'mcp-sync': { args: '', summary: 'Print harness
|
|
251
|
-
doctor: { args: '[--harness]', summary: 'Check prerequisites and runtime health (--harness: print harness
|
|
250
|
+
'mcp-sync': { args: '', summary: 'Print runtime harness inventory (same source as `minions doctor --harness`; read-only, no writes)' },
|
|
251
|
+
doctor: { args: '[--harness]', summary: 'Check prerequisites and runtime health (--harness: print runtime harness inventory)' },
|
|
252
252
|
config: { args: 'set-cli <R> [--model M]', summary: 'Persist defaultCli/defaultModel without starting' },
|
|
253
|
-
pr: { args: 'comment <repo> <prNumber> --agent <id> --kind <k> [--wi <id>] [--resolved] [--
|
|
253
|
+
pr: { args: 'comment <repo> <prNumber> --agent <id> --kind <k> [--wi <id>] [--resolved] [--body-file <f>|--body <text>]', summary: 'Post a marker-prepended PR comment via gh (ADO: --resolved posts pre-closed)' },
|
|
254
254
|
bridge: { args: 'status|health|enable|disable', summary: 'Constellation bridge: toggle and inspect the read-only cross-repo feed' },
|
|
255
255
|
});
|
|
256
256
|
|
|
@@ -413,111 +413,6 @@ function _applyRuntimeFlags({ cli, model, modelExplicit }) {
|
|
|
413
413
|
return { warnings, applied: true };
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
-
// resolveHarnessUsedForComment(flags) — P-7a3c9e21. Turn the `minions pr comment`
|
|
417
|
-
// harness flags into a grounded `harnessUsed` record suitable for the posters'
|
|
418
|
-
// `harnessUsed` param (engine/gh-comment.js / engine/ado-comment.js), which fold
|
|
419
|
-
// it via buildMinionsCommentBody -> buildHarnessUsedSection.
|
|
420
|
-
//
|
|
421
|
-
// Source precedence: `--harness-file <path>` (JSON on disk) wins over the inline
|
|
422
|
-
// `--harness-json <json>` convenience; neither supplied -> returns undefined so
|
|
423
|
-
// the comment body is byte-identical to today (no section). Read/parse failures
|
|
424
|
-
// are HARD errors (process.exit(2) with the offending message) — never a silent
|
|
425
|
-
// drop. Grounding uses the spawn-time `_harnessPropagated` manifest located by
|
|
426
|
-
// dispatch id (explicit `--dispatch-id` -> else basename(MINIONS_COMPLETION_REPORT,
|
|
427
|
-
// '.json')); an unresolvable manifest passes null, marking every entry
|
|
428
|
-
// grounded:false — the honest "no record" state, not a fatal condition.
|
|
429
|
-
function resolveHarnessUsedForComment(flags) {
|
|
430
|
-
const fileArg = flags['harness-file'];
|
|
431
|
-
const jsonArg = flags['harness-json'];
|
|
432
|
-
|
|
433
|
-
let raw;
|
|
434
|
-
if (fileArg !== undefined) {
|
|
435
|
-
try {
|
|
436
|
-
raw = fs.readFileSync(fileArg, 'utf8');
|
|
437
|
-
} catch (e) {
|
|
438
|
-
console.error(`error: could not read --harness-file ${fileArg}: ${e.message}`);
|
|
439
|
-
process.exit(2);
|
|
440
|
-
}
|
|
441
|
-
} else if (jsonArg !== undefined) {
|
|
442
|
-
raw = String(jsonArg);
|
|
443
|
-
} else {
|
|
444
|
-
return undefined;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
let parsed;
|
|
448
|
-
try {
|
|
449
|
-
parsed = JSON.parse(raw);
|
|
450
|
-
} catch (e) {
|
|
451
|
-
const src = fileArg !== undefined ? `--harness-file ${fileArg}` : '--harness-json';
|
|
452
|
-
console.error(`error: invalid JSON in ${src}: ${e.message}`);
|
|
453
|
-
process.exit(2);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Resolve the grounding manifest best-effort: explicit id -> completion-report
|
|
457
|
-
// basename. A missing/unresolvable manifest is non-fatal (groundHarnessUsed
|
|
458
|
-
// with null propagated marks everything grounded:false).
|
|
459
|
-
const dispatchId = flags['dispatch-id']
|
|
460
|
-
|| path.basename(process.env.MINIONS_COMPLETION_REPORT || '', '.json')
|
|
461
|
-
|| undefined;
|
|
462
|
-
let propagated = null;
|
|
463
|
-
if (dispatchId) {
|
|
464
|
-
try {
|
|
465
|
-
const dispatch = getDispatch();
|
|
466
|
-
for (const queue of ['active', 'completed', 'pending']) {
|
|
467
|
-
const list = Array.isArray(dispatch?.[queue]) ? dispatch[queue] : null;
|
|
468
|
-
if (!list) continue;
|
|
469
|
-
const found = list.find(d => d && d.id === dispatchId);
|
|
470
|
-
if (found && found._harnessPropagated) { propagated = found._harnessPropagated; break; }
|
|
471
|
-
}
|
|
472
|
-
} catch { propagated = null; }
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
return shared.groundHarnessUsed(parsed, propagated);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// resolveSkillSkippedForComment(flags) — W-mr287sc0000uc214. Turn the
|
|
479
|
-
// `minions pr comment` skip flags into a canonical `{name, reason}` record for
|
|
480
|
-
// the posters' `skillSkipped` param (engine/gh-comment.js / engine/ado-comment.js),
|
|
481
|
-
// which fold it via buildMinionsCommentBody -> buildSkippedSkillSection into a
|
|
482
|
-
// VISIBLE callout in the same comment as the verdict.
|
|
483
|
-
//
|
|
484
|
-
// Source precedence mirrors the harness resolver: `--skill-skipped-file <path>`
|
|
485
|
-
// (JSON on disk) wins over the inline `--skill-skipped-json <json>`; neither
|
|
486
|
-
// supplied -> returns undefined so the comment body is byte-identical to today
|
|
487
|
-
// (no callout). Read/parse failures are HARD errors (process.exit(2)). Accepts
|
|
488
|
-
// the raw `{name, reason}` shape or a `meta.skill` / `meta.review` wrapper; a
|
|
489
|
-
// record with no non-empty `name` yields undefined (nothing to surface).
|
|
490
|
-
function resolveSkillSkippedForComment(flags) {
|
|
491
|
-
const fileArg = flags['skill-skipped-file'];
|
|
492
|
-
const jsonArg = flags['skill-skipped-json'];
|
|
493
|
-
|
|
494
|
-
let raw;
|
|
495
|
-
if (fileArg !== undefined) {
|
|
496
|
-
try {
|
|
497
|
-
raw = fs.readFileSync(fileArg, 'utf8');
|
|
498
|
-
} catch (e) {
|
|
499
|
-
console.error(`error: could not read --skill-skipped-file ${fileArg}: ${e.message}`);
|
|
500
|
-
process.exit(2);
|
|
501
|
-
}
|
|
502
|
-
} else if (jsonArg !== undefined) {
|
|
503
|
-
raw = String(jsonArg);
|
|
504
|
-
} else {
|
|
505
|
-
return undefined;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
let parsed;
|
|
509
|
-
try {
|
|
510
|
-
parsed = JSON.parse(raw);
|
|
511
|
-
} catch (e) {
|
|
512
|
-
const src = fileArg !== undefined ? `--skill-skipped-file ${fileArg}` : '--skill-skipped-json';
|
|
513
|
-
console.error(`error: invalid JSON in ${src}: ${e.message}`);
|
|
514
|
-
process.exit(2);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const { _extractSkillSkipped } = require('./comment-format');
|
|
518
|
-
return _extractSkillSkipped(parsed) || undefined;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
416
|
const commands = {
|
|
522
417
|
start(...startArgs) {
|
|
523
418
|
// Apply --cli / --model fleet flags before any engine wiring touches
|
|
@@ -539,18 +434,6 @@ const commands = {
|
|
|
539
434
|
throw err;
|
|
540
435
|
}
|
|
541
436
|
|
|
542
|
-
// Startup state-file size guard (#1167): dispatch.json / cooldowns.json
|
|
543
|
-
// bloated past 100 MB silently OOMed V8 on JSON.parse at startup. Fail fast
|
|
544
|
-
// with an actionable message instead.
|
|
545
|
-
try {
|
|
546
|
-
for (const fp of [DISPATCH_PATH, path.join(ENGINE_DIR, 'cooldowns.json')]) {
|
|
547
|
-
shared.assertStateFileSize(fp);
|
|
548
|
-
}
|
|
549
|
-
} catch (stateErr) {
|
|
550
|
-
console.error('\n[engine] STARTUP ABORTED — ' + stateErr.message + '\n');
|
|
551
|
-
process.exit(78); // 78 = configuration error
|
|
552
|
-
}
|
|
553
|
-
|
|
554
437
|
// Run preflight checks (warn but don't block — engine may still be useful)
|
|
555
438
|
try {
|
|
556
439
|
const { runPreflight, printPreflight } = require('./preflight');
|
|
@@ -667,10 +550,7 @@ const commands = {
|
|
|
667
550
|
}
|
|
668
551
|
} catch (err) { e.log('warn', `note-link backfill failed: ${err.message}`); }
|
|
669
552
|
|
|
670
|
-
// Backfill work_items.prd_item_id
|
|
671
|
-
// the dual-write stamp (#546) or that a JSON re-hydrate transiently zeroed.
|
|
672
|
-
// Set-based, only touches NULL FKs, no-op once everything is linked — safe on
|
|
673
|
-
// every boot. Lets the Phase-10 render join move off the feature-id string.
|
|
553
|
+
// Backfill work_items.prd_item_id for rows created before FK stamping.
|
|
674
554
|
try {
|
|
675
555
|
const fk = require('./prd-store').backfillWorkItemPrdItemIds();
|
|
676
556
|
const filled = (fk.byWorkItemId || 0) + (fk.bySourcePlan || 0);
|
|
@@ -1211,22 +1091,7 @@ const commands = {
|
|
|
1211
1091
|
const _watchedFiles = new Set();
|
|
1212
1092
|
let _globalDebounce = null;
|
|
1213
1093
|
function watchForWorkChanges() {
|
|
1214
|
-
const filesToWatch = [
|
|
1215
|
-
path.join(MINIONS_DIR, 'work-items.json'),
|
|
1216
|
-
// dispatch.json excluded — it changes every tick, causing a feedback loop
|
|
1217
|
-
];
|
|
1218
|
-
// Watch project-specific work-items.json
|
|
1219
|
-
const { getProjects } = require('./shared');
|
|
1220
|
-
for (const p of getProjects(config)) {
|
|
1221
|
-
filesToWatch.push(shared.projectWorkItemsPath(p));
|
|
1222
|
-
}
|
|
1223
|
-
// Watch PRD files
|
|
1224
|
-
const prdDir = path.join(MINIONS_DIR, 'prd');
|
|
1225
|
-
try {
|
|
1226
|
-
for (const f of fs.readdirSync(prdDir).filter(f => f.endsWith('.json'))) {
|
|
1227
|
-
filesToWatch.push(path.join(prdDir, f));
|
|
1228
|
-
}
|
|
1229
|
-
} catch { /* optional */ }
|
|
1094
|
+
const filesToWatch = [];
|
|
1230
1095
|
|
|
1231
1096
|
for (const filePath of filesToWatch) {
|
|
1232
1097
|
if (_watchedFiles.has(filePath)) continue;
|
|
@@ -1465,8 +1330,8 @@ const commands = {
|
|
|
1465
1330
|
}
|
|
1466
1331
|
const flagFields = [
|
|
1467
1332
|
'claudeBareMode', 'claudeFallbackModel',
|
|
1468
|
-
'copilotDisableBuiltinMcps', '
|
|
1469
|
-
'
|
|
1333
|
+
'copilotDisableBuiltinMcps', 'copilotStreamMode', 'copilotReasoningSummaries',
|
|
1334
|
+
'claudePreApproveWorkspaceMcps',
|
|
1470
1335
|
'maxBudgetUsd', 'disableModelDiscovery',
|
|
1471
1336
|
'ccUseWorkerPool',
|
|
1472
1337
|
];
|
|
@@ -1488,14 +1353,13 @@ const commands = {
|
|
|
1488
1353
|
}
|
|
1489
1354
|
|
|
1490
1355
|
console.log('');
|
|
1491
|
-
const metrics =
|
|
1356
|
+
const metrics = queries.getMetrics();
|
|
1492
1357
|
const lifetimeCompleted = Object.entries(metrics).filter(([k]) => !k.startsWith('_')).reduce((sum, [, m]) => sum + (m.tasksCompleted || 0) + (m.tasksErrored || 0), 0);
|
|
1493
1358
|
console.log(`Dispatch: ${dispatch.pending.length} pending | ${(dispatch.active || []).length} active | ${lifetimeCompleted} completed`);
|
|
1494
1359
|
const pidSummary = summarizeActiveDispatchPids(dispatch.active || []);
|
|
1495
1360
|
console.log(`Active dispatch PID files: ${pidSummary.live} live | ${pidSummary.dead} dead | ${pidSummary.missing} missing`);
|
|
1496
1361
|
|
|
1497
|
-
const
|
|
1498
|
-
const metricsData = safeJson(metricsPath);
|
|
1362
|
+
const metricsData = queries.getMetrics();
|
|
1499
1363
|
if (metricsData && Object.keys(metricsData).length > 0) {
|
|
1500
1364
|
console.log('\nMetrics:');
|
|
1501
1365
|
console.log(` ${'Agent'.padEnd(12)} ${'Done'.padEnd(6)} ${'Err'.padEnd(6)} ${'PRs'.padEnd(6)} ${'Appr'.padEnd(6)} ${'Rej'.padEnd(6)} ${'Reviews'.padEnd(8)} ${'Cost'.padEnd(8)}`);
|
|
@@ -1989,7 +1853,7 @@ const commands = {
|
|
|
1989
1853
|
doctor(...doctorArgs) {
|
|
1990
1854
|
const { doctor, runHarnessDoctor } = require('./preflight');
|
|
1991
1855
|
if (doctorArgs.includes('--harness')) {
|
|
1992
|
-
//
|
|
1856
|
+
// Read-only runtime harness inventory. See
|
|
1993
1857
|
// docs/harness-propagation.md and the parallel branch in bin/minions.js.
|
|
1994
1858
|
const ok = runHarnessDoctor(MINIONS_DIR);
|
|
1995
1859
|
if (!ok) process.exit(1);
|
|
@@ -2086,19 +1950,9 @@ const commands = {
|
|
|
2086
1950
|
console.log('Usage:');
|
|
2087
1951
|
console.log(' GitHub: minions pr comment <repo> <prNumber> --agent <id> --kind <k> [--wi <id>] (--body-file <path> | --body <text>)');
|
|
2088
1952
|
console.log(' ADO: minions pr comment <prNumber> --host ado --ado-org <org> --ado-project <proj> --repo-id <id> --agent <id> --kind <k> [--wi <id>] (--body-file <path> | --body <text>)');
|
|
2089
|
-
console.log('');
|
|
2090
|
-
console.log('Optional harness self-report (folded into the collapsible "Harnesses used" section):');
|
|
2091
|
-
console.log(' --harness-file <path> JSON file with the { skills, mcpServers, commands, docs } record (wins over --harness-json)');
|
|
2092
|
-
console.log(' --harness-json <json> same record inline as a JSON string');
|
|
2093
|
-
console.log(' --dispatch-id <id> grounding manifest override (else basename of $MINIONS_COMPLETION_REPORT)');
|
|
2094
|
-
console.log('');
|
|
2095
|
-
console.log('Skipped in-scope project skill (folded in as a VISIBLE "⚠️ Skipped project skill" callout):');
|
|
2096
|
-
console.log(' --skill-skipped-file <path> JSON file with the { name, reason } skip record (wins over --skill-skipped-json)');
|
|
2097
|
-
console.log(' --skill-skipped-json <json> same record inline as a JSON string (also accepts a meta.skill/meta.review wrapper)');
|
|
2098
1953
|
console.log(' --resolved (ADO only) post the thread pre-resolved/closed — for non-actionable FYI/praise notes');
|
|
2099
1954
|
console.log('');
|
|
2100
|
-
console.log('Posts a PR comment with the hidden minions marker
|
|
2101
|
-
console.log('"Harnesses used" section, and the brand link folded in by the shared');
|
|
1955
|
+
console.log('Posts a PR comment with the hidden minions marker and brand link folded in by the shared');
|
|
2102
1956
|
console.log('builder — so engine classifiers identify agent-authored comments by');
|
|
2103
1957
|
console.log('structure, and the body is byte-identical on GitHub (`gh pr comment`)');
|
|
2104
1958
|
console.log('and Azure DevOps (REST `…/threads`).');
|
|
@@ -2162,18 +2016,6 @@ const commands = {
|
|
|
2162
2016
|
process.exit(2);
|
|
2163
2017
|
}
|
|
2164
2018
|
|
|
2165
|
-
// P-7a3c9e21 — thread the consulted-sources footprint into both posters so
|
|
2166
|
-
// the auto-folded "Harnesses used" <details> section the help already
|
|
2167
|
-
// promises is actually rendered. Resolved once (host-neutral); absent flags
|
|
2168
|
-
// -> undefined -> body byte-identical to today.
|
|
2169
|
-
const harnessUsed = resolveHarnessUsedForComment(flags);
|
|
2170
|
-
|
|
2171
|
-
// W-mr287sc0000uc214 — thread the skipped-in-scope-project-skill self-report
|
|
2172
|
-
// into both posters so it's surfaced as a VISIBLE callout in the same comment
|
|
2173
|
-
// as the verdict (not buried in the completion-report JSON). Absent flags
|
|
2174
|
-
// -> undefined -> body byte-identical to today.
|
|
2175
|
-
const skillSkipped = resolveSkillSkippedForComment(flags);
|
|
2176
|
-
|
|
2177
2019
|
// ── Azure DevOps: <prNumber> --host ado --ado-org --ado-project --repo-id ──
|
|
2178
2020
|
if (isAdo) {
|
|
2179
2021
|
const [prNumberRaw] = positional;
|
|
@@ -2193,7 +2035,7 @@ const commands = {
|
|
|
2193
2035
|
const orgBase = flags['org-base'] || `https://dev.azure.com/${adoOrg}`;
|
|
2194
2036
|
const adoComment = require('./ado-comment');
|
|
2195
2037
|
adoComment.postAdoPrComment({
|
|
2196
|
-
orgBase, project, repositoryId, prNumber, body, agentId, kind, workItemId,
|
|
2038
|
+
orgBase, project, repositoryId, prNumber, body, agentId, kind, workItemId,
|
|
2197
2039
|
resolved: flags.resolved === true,
|
|
2198
2040
|
}).then((result) => {
|
|
2199
2041
|
if (result && result.threadId) {
|
|
@@ -2232,7 +2074,7 @@ const commands = {
|
|
|
2232
2074
|
|
|
2233
2075
|
try {
|
|
2234
2076
|
const result = ghComment.postPrComment({
|
|
2235
|
-
repo, prNumber, body, agentId, kind, workItemId,
|
|
2077
|
+
repo, prNumber, body, agentId, kind, workItemId,
|
|
2236
2078
|
});
|
|
2237
2079
|
if (result.output) console.log(result.output);
|
|
2238
2080
|
} catch (e) {
|
|
@@ -2371,10 +2213,6 @@ module.exports = {
|
|
|
2371
2213
|
_readDispatchPid: readDispatchPid,
|
|
2372
2214
|
_normalizeSessionBranch: normalizeSessionBranch,
|
|
2373
2215
|
_dispatchSessionBranch: dispatchSessionBranch,
|
|
2374
|
-
// P-7a3c9e21 — harness-flag resolver exported for CLI-threading tests.
|
|
2375
|
-
_resolveHarnessUsedForComment: resolveHarnessUsedForComment,
|
|
2376
|
-
// W-mr287sc0000uc214 — skipped-project-skill flag resolver exported for tests.
|
|
2377
|
-
_resolveSkillSkippedForComment: resolveSkillSkippedForComment,
|
|
2378
2216
|
// W-mpcyvff6000pf828 (#2653) — heartbeat writer + factory exported for tests
|
|
2379
2217
|
_writeHeartbeatNow: writeHeartbeatNow,
|
|
2380
2218
|
_createHeartbeatInterval: createHeartbeatInterval,
|