@yemi33/minions 0.1.2424 → 0.1.2426
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/install-internal-minions.js +1209 -0
- package/bin/minions.js +75 -9
- package/dashboard/docs/typography.md +27 -12
- package/dashboard/js/command-center.js +13 -11
- package/dashboard/js/live-stream.js +1 -1
- package/dashboard/js/memory-search.js +388 -43
- package/dashboard/js/modal-qa.js +5 -5
- package/dashboard/js/qa.js +39 -26
- package/dashboard/js/refresh.js +37 -18
- package/dashboard/js/render-agents.js +14 -18
- package/dashboard/js/render-dispatch.js +14 -74
- package/dashboard/js/render-inbox.js +3 -3
- package/dashboard/js/render-meetings.js +8 -8
- package/dashboard/js/render-other.js +45 -20
- package/dashboard/js/render-pipelines.js +6 -6
- package/dashboard/js/render-plans.js +14 -14
- package/dashboard/js/render-prd.js +46 -46
- package/dashboard/js/render-prs.js +9 -65
- package/dashboard/js/render-schedules.js +5 -5
- package/dashboard/js/render-skills.js +6 -6
- package/dashboard/js/render-utils.js +4 -4
- package/dashboard/js/render-watches.js +4 -16
- package/dashboard/js/render-work-items.js +95 -107
- package/dashboard/js/settings.js +175 -74
- package/dashboard/layout.html +3 -2
- package/dashboard/pages/inbox.html +1 -1
- package/dashboard/pages/work.html +1 -1
- package/dashboard/shared/model-display.js +9 -0
- package/dashboard/shared/watches-source.js +43 -0
- package/dashboard/shared/welcome-popup.js +259 -0
- package/dashboard/slim/body.html +6 -6
- package/dashboard/slim/js/chat.js +4 -2
- package/dashboard/slim/js/history.js +10 -3
- package/dashboard/slim/js/modals-tiles.js +85 -16
- package/dashboard/slim/js/status.js +12 -16
- package/dashboard/slim/styles.css +24 -4
- package/dashboard/styles.css +62 -27
- package/dashboard-build.js +8 -2
- package/dashboard.js +3854 -2514
- package/docs/README.md +7 -5
- package/docs/api-errors.md +144 -0
- package/docs/auto-discovery.md +83 -61
- package/docs/capture-demos.js +173 -30
- package/docs/command-center.md +5 -1
- package/docs/completion-reports.md +127 -11
- package/docs/constants.md +15 -3
- package/docs/constellation-style-telemetry.md +2 -2
- package/docs/copilot-cli-schema.md +32 -22
- package/docs/cross-repo-plans.md +30 -30
- package/docs/demo/memory-system.html +1 -1
- package/docs/deprecated.json +132 -18
- package/docs/diagnostics-memory.md +8 -4
- package/docs/human-vs-automated.md +2 -2
- package/docs/index.html +9 -2
- package/docs/internal-install.md +212 -0
- package/docs/kb-pr3223-cascade-archiving.md +16 -0
- package/docs/kb-pr696-merge-conflict-docs.md +23 -0
- package/docs/kb-sweep.md +2 -2
- package/docs/keep-processes.md +8 -1
- package/docs/live-checkout-mode.md +1 -1
- package/docs/managed-spawn.md +21 -3
- package/docs/named-agents.md +3 -2
- package/docs/onboarding.md +26 -0
- package/docs/plan-lifecycle.md +32 -32
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
- package/docs/qa-runbook-lifecycle.md +67 -51
- package/docs/qa-runbooks.md +2 -2
- package/docs/runtime-adapters.md +101 -50
- package/docs/security.md +28 -0
- package/docs/self-improvement.md +47 -13
- package/docs/skills.md +29 -0
- package/docs/slim-ux/concepts.md +2 -2
- package/docs/specs/agent-configurability.md +43 -41
- package/docs/specs/agent-rename.md +13 -13
- package/docs/team-memory.md +283 -14
- package/docs/tutorials/01-install-and-connect.md +23 -0
- package/docs/tutorials/03-plan-driven-feature.md +3 -3
- package/docs/tutorials/04-runtimes-and-harness.md +18 -21
- package/docs/tutorials/08-operations-and-recovery.md +3 -2
- package/docs/tutorials/README.md +4 -3
- package/docs/visual-evidence-ci.md +103 -0
- package/docs/watches.md +35 -30
- package/docs/worktree-lifecycle.md +151 -13
- package/engine/acp-transport.js +1 -0
- package/engine/ado.js +80 -33
- package/engine/agent-api-validation.js +571 -0
- package/engine/agent-worker-pool.js +7 -6
- package/engine/api-contracts/agent-content.js +761 -0
- package/engine/api-contracts/cc-ops.js +219 -0
- package/engine/api-contracts/config-runtime.js +419 -0
- package/engine/api-contracts/core.js +138 -0
- package/engine/api-contracts/index.js +506 -0
- package/engine/api-contracts/orchestration.js +602 -0
- package/engine/api-contracts/pull-requests.js +323 -0
- package/engine/api-contracts/qa-process.js +764 -0
- package/engine/api-contracts/work-plan-prd.js +494 -0
- package/engine/api-validation.js +543 -0
- package/engine/cc-api-validation.js +586 -0
- package/engine/cc-worker-pool.js +9 -1
- package/engine/cleanup.js +393 -271
- package/engine/cli.js +65 -7
- package/engine/comment-classifier.js +70 -5
- package/engine/consolidation.js +123 -5
- package/engine/content-api-validation.js +606 -0
- package/engine/create-pr-worktree.js +22 -1
- package/engine/db/migrations/027-review-learning-lifecycle.js +162 -0
- package/engine/dispatch.js +33 -0
- package/engine/distribution.js +189 -0
- package/engine/execution-model.js +59 -0
- package/engine/features.js +12 -0
- package/engine/github.js +67 -25
- package/engine/harness-context.js +313 -0
- package/engine/inbox-store.js +1 -1
- package/engine/kb-sweep.js +161 -38
- package/engine/keep-process-sweep.js +43 -3
- package/engine/lifecycle.js +1066 -165
- package/engine/llm.js +4 -0
- package/engine/managed-spawn.js +463 -48
- package/engine/meeting.js +197 -34
- package/engine/memory-retrieval.js +280 -0
- package/engine/memory-store.js +821 -38
- package/engine/model-discovery.js +17 -3
- package/engine/pipeline.js +802 -14
- package/engine/plan-prd-validation.js +745 -0
- package/engine/playbook.js +206 -17
- package/engine/pooled-agent-process.js +6 -1
- package/engine/pr-action.js +1 -1
- package/engine/pr-issue-validation.js +653 -0
- package/engine/pr-resolve.js +75 -13
- package/engine/prd-store.js +39 -6
- package/engine/preflight.js +7 -2
- package/engine/process-utils.js +79 -31
- package/engine/projects.js +198 -12
- package/engine/promotion.js +371 -0
- package/engine/qa-from-prd.js +3 -0
- package/engine/qa-process-validation.js +572 -0
- package/engine/qa-runbooks.js +41 -37
- package/engine/qa-runners/maestro.js +11 -7
- package/engine/qa-runners/playwright.js +37 -14
- package/engine/qa-runners.js +9 -10
- package/engine/qa-runs.js +124 -11
- package/engine/qa-sessions.js +139 -40
- package/engine/quarantine-refs.js +81 -11
- package/engine/queries.js +163 -9
- package/engine/review-learning-backfill.js +482 -0
- package/engine/review-learning.js +1236 -0
- package/engine/runtimes/claude.js +60 -2
- package/engine/runtimes/codex.js +57 -16
- package/engine/runtimes/contract.js +21 -0
- package/engine/runtimes/copilot.js +51 -3
- package/engine/runtimes/index.js +1 -0
- package/engine/scheduler.js +201 -32
- package/engine/settings-validation.js +909 -0
- package/engine/shared.js +705 -208
- package/engine/spawn-agent.js +48 -21
- package/engine/steering-constraints.js +31 -0
- package/engine/steering-store.js +10 -2
- package/engine/steering.js +14 -2
- package/engine/timeout.js +404 -111
- package/engine/untrusted-fence.js +24 -10
- package/engine/watch-actions.js +7 -2
- package/engine/watches.js +353 -51
- package/engine/work-item-validation.js +561 -0
- package/engine/work-items-store.js +61 -1
- package/engine/worktree-gc.js +656 -37
- package/engine/worktree-preflight.js +154 -0
- package/engine.js +2068 -342
- package/package.json +1 -1
- package/playbooks/_pr-description-audit.md +88 -41
- package/playbooks/build-fix-complex.md +3 -3
- package/playbooks/docs.md +2 -2
- package/playbooks/fix.md +18 -18
- package/playbooks/implement.md +18 -18
- package/playbooks/qa-session-draft.md +10 -12
- package/playbooks/qa-session-execute.md +16 -12
- package/playbooks/qa-validate.md +8 -7
- package/playbooks/shared-rules.md +45 -0
- package/playbooks/test.md +4 -0
- package/prompts/cc-system.md +1 -1
- package/skills/check-self-authored-review-comment/SKILL.md +2 -2
package/docs/capture-demos.js
CHANGED
|
@@ -7,80 +7,182 @@
|
|
|
7
7
|
* Requires: dashboard running on :7331, playwright chromium installed
|
|
8
8
|
*/
|
|
9
9
|
const { chromium } = require('@playwright/test');
|
|
10
|
-
const {
|
|
10
|
+
const { execFileSync } = require('child_process');
|
|
11
|
+
const fs = require('fs');
|
|
11
12
|
const path = require('path');
|
|
12
13
|
|
|
13
14
|
const DEMO_DIR = path.join(__dirname, 'demo');
|
|
14
|
-
const
|
|
15
|
+
const DEFAULT_BASE_URL = 'http://localhost:7331';
|
|
15
16
|
const ROOT = path.resolve(__dirname, '..');
|
|
17
|
+
const SCREENSHOT_FILES = Object.freeze([
|
|
18
|
+
'01-dashboard-overview.png',
|
|
19
|
+
'02-work-items.png',
|
|
20
|
+
'03-plans-prd.png',
|
|
21
|
+
'04-pull-requests.png',
|
|
22
|
+
'05-meetings.png',
|
|
23
|
+
'06-pipelines.png',
|
|
24
|
+
'07-notes-kb.png',
|
|
25
|
+
'08-schedules.png',
|
|
26
|
+
'09-engine.png',
|
|
27
|
+
'10-command-center.png',
|
|
28
|
+
]);
|
|
16
29
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
30
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
31
|
+
const options = {
|
|
32
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
33
|
+
outputDir: DEMO_DIR,
|
|
34
|
+
stateDir: null,
|
|
35
|
+
skipSeed: false,
|
|
36
|
+
fixedTime: null,
|
|
37
|
+
};
|
|
38
|
+
const valueFor = (flag, index) => {
|
|
39
|
+
const value = argv[index + 1];
|
|
40
|
+
if (!value || value.startsWith('--')) throw new Error(`${flag} requires a value`);
|
|
41
|
+
return value;
|
|
42
|
+
};
|
|
21
43
|
|
|
22
|
-
|
|
23
|
-
|
|
44
|
+
for (let i = 0; i < argv.length; i++) {
|
|
45
|
+
switch (argv[i]) {
|
|
46
|
+
case '--base-url':
|
|
47
|
+
options.baseUrl = valueFor(argv[i], i);
|
|
48
|
+
i++;
|
|
49
|
+
break;
|
|
50
|
+
case '--output-dir':
|
|
51
|
+
options.outputDir = path.resolve(valueFor(argv[i], i));
|
|
52
|
+
i++;
|
|
53
|
+
break;
|
|
54
|
+
case '--state-dir':
|
|
55
|
+
options.stateDir = path.resolve(valueFor(argv[i], i));
|
|
56
|
+
i++;
|
|
57
|
+
break;
|
|
58
|
+
case '--fixed-time':
|
|
59
|
+
options.fixedTime = valueFor(argv[i], i);
|
|
60
|
+
if (!Number.isFinite(Date.parse(options.fixedTime))) {
|
|
61
|
+
throw new Error('--fixed-time must be an ISO-8601 timestamp');
|
|
62
|
+
}
|
|
63
|
+
i++;
|
|
64
|
+
break;
|
|
65
|
+
case '--skip-seed':
|
|
66
|
+
options.skipSeed = true;
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
throw new Error(`Unknown argument: ${argv[i]}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return options;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function runSeed({ clean = false, stateDir = null } = {}) {
|
|
76
|
+
const args = [path.join(ROOT, 'test', 'seed-demo-data.js')];
|
|
77
|
+
if (clean) args.push('--clean');
|
|
78
|
+
if (stateDir) args.push('--state-dir', stateDir);
|
|
79
|
+
execFileSync(process.execPath, args, { stdio: 'inherit' });
|
|
80
|
+
}
|
|
24
81
|
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
82
|
+
async function capture(options = {}) {
|
|
83
|
+
const {
|
|
84
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
85
|
+
outputDir = DEMO_DIR,
|
|
86
|
+
stateDir = null,
|
|
87
|
+
skipSeed = false,
|
|
88
|
+
fixedTime = null,
|
|
89
|
+
} = options;
|
|
90
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
28
91
|
|
|
92
|
+
let browser;
|
|
93
|
+
let seedAttempted = false;
|
|
94
|
+
let captureError = null;
|
|
29
95
|
try {
|
|
30
|
-
|
|
96
|
+
if (!skipSeed) {
|
|
97
|
+
console.log(' Seeding demo data...');
|
|
98
|
+
seedAttempted = true;
|
|
99
|
+
runSeed({ stateDir });
|
|
100
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
browser = await chromium.launch({ headless: true });
|
|
104
|
+
const ctx = await browser.newContext({
|
|
105
|
+
viewport: { width: 1400, height: 900 },
|
|
106
|
+
colorScheme: 'dark',
|
|
107
|
+
locale: 'en-US',
|
|
108
|
+
timezoneId: 'UTC',
|
|
109
|
+
reducedMotion: 'reduce',
|
|
110
|
+
});
|
|
111
|
+
if (fixedTime) {
|
|
112
|
+
const now = Date.parse(fixedTime);
|
|
113
|
+
await ctx.addInitScript(({ timestamp }) => {
|
|
114
|
+
const NativeDate = Date;
|
|
115
|
+
class FixedDate extends NativeDate {
|
|
116
|
+
constructor(...args) {
|
|
117
|
+
super(...(args.length ? args : [timestamp]));
|
|
118
|
+
}
|
|
119
|
+
static now() { return timestamp; }
|
|
120
|
+
}
|
|
121
|
+
Object.setPrototypeOf(FixedDate, NativeDate);
|
|
122
|
+
globalThis.Date = FixedDate;
|
|
123
|
+
}, { timestamp: now });
|
|
124
|
+
}
|
|
125
|
+
const page = await ctx.newPage();
|
|
126
|
+
const screenshot = (file, { fullPage = false } = {}) => page.screenshot({
|
|
127
|
+
path: path.join(outputDir, file),
|
|
128
|
+
fullPage,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
await page.goto(baseUrl, { waitUntil: 'networkidle' });
|
|
31
132
|
await page.waitForTimeout(3000);
|
|
32
133
|
|
|
33
134
|
// 1. Home / Overview (agents should show as working from seeded dispatches)
|
|
34
135
|
console.log(' Capturing: home');
|
|
35
|
-
await
|
|
136
|
+
await screenshot(SCREENSHOT_FILES[0]);
|
|
36
137
|
|
|
37
138
|
// 2. Work Items
|
|
38
139
|
console.log(' Capturing: work items');
|
|
39
140
|
await page.click('a[data-page="work"]');
|
|
40
141
|
await page.waitForTimeout(2000);
|
|
41
|
-
await
|
|
142
|
+
await screenshot(SCREENSHOT_FILES[1]);
|
|
42
143
|
|
|
43
144
|
// 3. Plans & PRD (seeded PRD with dependency graph)
|
|
44
145
|
console.log(' Capturing: plans & PRD');
|
|
45
146
|
await page.click('a[data-page="plans"]');
|
|
46
147
|
await page.waitForTimeout(2000);
|
|
47
|
-
await
|
|
148
|
+
await screenshot(SCREENSHOT_FILES[2]);
|
|
48
149
|
|
|
49
150
|
// 4. Pull Requests
|
|
50
151
|
console.log(' Capturing: pull requests');
|
|
51
152
|
await page.click('a[data-page="prs"]');
|
|
52
153
|
await page.waitForTimeout(1500);
|
|
53
|
-
await
|
|
154
|
+
await screenshot(SCREENSHOT_FILES[3]);
|
|
54
155
|
|
|
55
156
|
// 5. Meetings
|
|
56
157
|
console.log(' Capturing: meetings');
|
|
57
158
|
await page.click('a[data-page="meetings"]');
|
|
58
159
|
await page.waitForTimeout(1500);
|
|
59
|
-
await
|
|
160
|
+
await screenshot(SCREENSHOT_FILES[4]);
|
|
60
161
|
|
|
61
162
|
// 6. Pipelines
|
|
62
163
|
console.log(' Capturing: pipelines');
|
|
63
164
|
await page.click('a[data-page="pipelines"]');
|
|
64
165
|
await page.waitForTimeout(1500);
|
|
65
|
-
await
|
|
166
|
+
await screenshot(SCREENSHOT_FILES[5]);
|
|
66
167
|
|
|
67
168
|
// 7. Notes & KB
|
|
68
169
|
console.log(' Capturing: notes & KB');
|
|
69
170
|
await page.click('a[data-page="inbox"]');
|
|
70
171
|
await page.waitForTimeout(1500);
|
|
71
|
-
await
|
|
172
|
+
await screenshot(SCREENSHOT_FILES[6]);
|
|
72
173
|
|
|
73
174
|
// 8. Schedules
|
|
74
175
|
console.log(' Capturing: schedules');
|
|
75
176
|
await page.click('a[data-page="schedule"]');
|
|
76
177
|
await page.waitForTimeout(1500);
|
|
77
|
-
await
|
|
178
|
+
await screenshot(SCREENSHOT_FILES[7]);
|
|
78
179
|
|
|
79
|
-
// 9. Engine page (dispatch, log, metrics)
|
|
180
|
+
// 9. Engine page (dispatch, log, metrics) — full-page so below-the-fold
|
|
181
|
+
// panels (Keep-Processes, Quarantined Work, Managed Processes) are captured.
|
|
80
182
|
console.log(' Capturing: engine');
|
|
81
183
|
await page.click('a[data-page="engine"]');
|
|
82
184
|
await page.waitForTimeout(1500);
|
|
83
|
-
await
|
|
185
|
+
await screenshot(SCREENSHOT_FILES[8], { fullPage: true });
|
|
84
186
|
|
|
85
187
|
// 10. Command Center with mock conversation
|
|
86
188
|
console.log(' Capturing: command center');
|
|
@@ -131,17 +233,58 @@ async function capture() {
|
|
|
131
233
|
el.scrollTop = el.scrollHeight;
|
|
132
234
|
});
|
|
133
235
|
await page.waitForTimeout(500);
|
|
134
|
-
await
|
|
236
|
+
await screenshot(SCREENSHOT_FILES[9]);
|
|
135
237
|
|
|
238
|
+
for (const file of SCREENSHOT_FILES) {
|
|
239
|
+
const screenshotPath = path.join(outputDir, file);
|
|
240
|
+
if (!fs.existsSync(screenshotPath) || fs.statSync(screenshotPath).size === 0) {
|
|
241
|
+
throw new Error(`Capture did not produce ${file}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
captureError = error;
|
|
136
246
|
} finally {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
247
|
+
if (browser) {
|
|
248
|
+
try {
|
|
249
|
+
await browser.close();
|
|
250
|
+
} catch (closeError) {
|
|
251
|
+
if (!captureError) captureError = closeError;
|
|
252
|
+
else console.error(` Browser cleanup failed: ${closeError.message}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (seedAttempted) {
|
|
256
|
+
console.log(' Cleaning demo data...');
|
|
257
|
+
try {
|
|
258
|
+
runSeed({ clean: true, stateDir });
|
|
259
|
+
} catch (cleanupError) {
|
|
260
|
+
if (!captureError) captureError = cleanupError;
|
|
261
|
+
else console.error(` Cleanup failed: ${cleanupError.message}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
142
264
|
}
|
|
143
265
|
|
|
144
|
-
|
|
266
|
+
if (captureError) throw captureError;
|
|
267
|
+
console.log(`\n Done! Screenshots saved to ${outputDir}`);
|
|
268
|
+
return SCREENSHOT_FILES.map(file => path.join(outputDir, file));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (require.main === module) {
|
|
272
|
+
let options;
|
|
273
|
+
try {
|
|
274
|
+
options = parseArgs();
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.error(error.message);
|
|
277
|
+
process.exit(2);
|
|
278
|
+
}
|
|
279
|
+
capture(options).catch(error => {
|
|
280
|
+
console.error(error);
|
|
281
|
+
process.exit(1);
|
|
282
|
+
});
|
|
145
283
|
}
|
|
146
284
|
|
|
147
|
-
|
|
285
|
+
module.exports = {
|
|
286
|
+
DEFAULT_BASE_URL,
|
|
287
|
+
SCREENSHOT_FILES,
|
|
288
|
+
parseArgs,
|
|
289
|
+
capture,
|
|
290
|
+
};
|
package/docs/command-center.md
CHANGED
|
@@ -36,7 +36,7 @@ Canonical envelope (`_buildCcErrorEnvelope` in `dashboard.js`):
|
|
|
36
36
|
```json
|
|
37
37
|
{ "type": "error",
|
|
38
38
|
"message": "Human-readable cause + remediation hint",
|
|
39
|
-
"code": "model-unavailable | auth-failure | context-limit | budget-exceeded | crash | cc-turn-timeout | worker-spawn-failed | acp-handshake-failed | worker-died | invalid-image",
|
|
39
|
+
"code": "model-unavailable | auth-failure | context-limit | budget-exceeded | crash | cc-turn-timeout | worker-spawn-failed | acp-handshake-failed | worker-died | invalid-request | invalid-image",
|
|
40
40
|
"retryable": false,
|
|
41
41
|
"availableModels": ["gpt-4o", "gpt-5.4", "..."],
|
|
42
42
|
"runtime": "copilot"
|
|
@@ -45,6 +45,10 @@ Canonical envelope (`_buildCcErrorEnvelope` in `dashboard.js`):
|
|
|
45
45
|
|
|
46
46
|
`code` is clamped to the allowlist (`CC_ERROR_CODES` constant); unknown codes collapse to `crash`. `retryable: true` is informational — there is **no auto-retry**; the dashboard always offers a manual Retry button instead. Auto-retrying these errors is a footgun because most are operator-fix categories (auth, budget, missing model) where re-spawning makes no progress.
|
|
47
47
|
|
|
48
|
+
**Request validation.** Command Center and Doc-Chat validate the complete JSON payload before rate-limit accounting, in-flight reservations, worker acquisition, LLM calls, session mutation, document reads/edits, or SSE headers. Rejections use the same typed envelope with `code: "invalid-request"`, `retryable: false`, and shared `field` / `path` / `details` constraints. Transcripts are capped at 20 typed `{role,text}` entries; tab/session IDs, booleans, messages, documents, selections, content hashes, and image metadata are bounded and type-checked. Streaming reconnects accept only `tabId`, optional `sessionId`, and `reconnect: true`.
|
|
49
|
+
|
|
50
|
+
Doc-Chat editable paths must be relative, remain inside the Minions root after real-path resolution, avoid symlinks/junctions and protected live runtime files, and belong to a document context such as `plans/`, `prd/`, `projects/`, `knowledge/`, `notes/`, `meetings/`, or `skills/`. Validation returns the resolved path once and handlers reuse it after acquiring the document reservation.
|
|
51
|
+
|
|
48
52
|
**Watchdog (`engine.ccTurnTimeoutMs`, default 5 min, clamped 10s–1h).** Per-turn **no-progress** cap. Each turn arms a `setTimeout` that fires `event: error` with `code: 'cc-turn-timeout'`, aborts the in-flight LLM call, and ends the stream when no liveness signal arrives within the window. The timer **resets on every progress event** — token chunk, tool-call notification, tool-update — so a turn that's actively streaming or running long tools (e.g. `Bash` running `npm test`, `WebFetch`/`WebSearch` against slow targets, agent sub-dispatches) survives indefinitely up to the outer 1h `CC_CALL_TIMEOUT_MS` hard ceiling. Wired via `liveState._bumpTimer` (CC stream path) and the factory shape of `_raceCcDocChatTimeout` (doc-chat stream path); the non-streaming doc-chat path has no progress hooks and retains wall-clock semantics. Surfaced in Settings → CC overrides.
|
|
49
53
|
|
|
50
54
|
**No auto-retry policy.** The backend never re-spawns the LLM after an error envelope. The client never silently resends the user's turn. Retry is a single-click manual action — guards against silent budget burn on `budget-exceeded`, infinite loops on `auth-failure`, and accidental re-charges on `context-limit`. The 429 + reconnect paths (rate-limited fetch retry, SSE reconnect-after-disconnect) remain — those are transport-level, not error-envelope-level.
|
|
@@ -21,6 +21,15 @@ Path shape (resolved by `shared.dispatchCompletionReportPath()` in `engine/share
|
|
|
21
21
|
|
|
22
22
|
The agent must write the JSON to that exact path before exiting. Any character outside `[a-zA-Z0-9._-]` in the dispatch id is replaced with `-` by the engine when computing the path.
|
|
23
23
|
|
|
24
|
+
For a mutating dispatch, process exit code `0` is only a transport signal. If
|
|
25
|
+
the JSON file is absent, malformed, or has a status outside the documented
|
|
26
|
+
success/nonterminal enums, the engine keeps the worker in
|
|
27
|
+
`Process exited; validating completion`, then records an error with
|
|
28
|
+
`failure_class: 'completion-report-missing'`. It still runs the PR-attachment
|
|
29
|
+
contract, so a simultaneous missing PR remains visible rather than being
|
|
30
|
+
replaced by the report failure. Nonzero exits retain their original runtime
|
|
31
|
+
failure classification; a missing report does not mask that error.
|
|
32
|
+
|
|
24
33
|
## Trust boundary
|
|
25
34
|
|
|
26
35
|
Each spawn also receives a per-dispatch cryptographic value named
|
|
@@ -92,12 +101,112 @@ Do **not** invent, regenerate, or share the nonce across dispatches — each spa
|
|
|
92
101
|
| `noopReason` | string | Human-readable rationale shown when `noop: true`. Falls back to `summary` if absent. |
|
|
93
102
|
| `reviewFindingResolution` | object | Required when a review-feedback fix leaves the PR branch unchanged. Shape: `{findingId, disposition, currentCodeEvidence}`; see [Review-fix no-op evidence](#review-fix-no-op-evidence). |
|
|
94
103
|
| `files_changed` | string \| array | Comma-separated list (or array) of key files changed. |
|
|
104
|
+
| `not_changed` | string | Scope boundary: adjacent work deliberately left untouched and why. |
|
|
95
105
|
| `affected_files` | string[] | Optional array of relative file paths this dispatch touched or plans to touch. Used by the dispatcher to emit a conflict warning (`WI <new-id> may conflict with in-progress <existing-id> on files: [list]`) when a new WI's `affected_files` overlaps with an in-progress WI's `affected_files`. Logging-only — dispatch is never blocked. Stored back onto the work item after completion so re-dispatches can also participate in overlap detection. |
|
|
96
106
|
| `tests` | string | `pass`, `fail`, `skipped`, `N/A`, or a free-form note like `skipped — relying on PR pipeline`. |
|
|
97
|
-
| `
|
|
107
|
+
| `securityFlags` | object | Set `{ "injectionAttempt": true }` after detecting an instruction-redirection attempt inside an `<UNTRUSTED-INPUT>` fence. The engine converts it to non-retryable `injection-flagged` and writes an alert. |
|
|
108
|
+
| `reviewLearnings` | array | Optional verified review lessons. At most eight entries; each entry is source-bound, redacted, type-checked, and byte-capped. See [Review-learning completion payloads](#review-learning-completion-payloads). |
|
|
109
|
+
| `reviewLearningApplications` | array | Optional outcomes for recalled review lessons. At most 32 entries; each contains a lesson ID, outcome label, and bounded evidence. |
|
|
98
110
|
| `followups` | array | Optional. PR-comment follow-up work items the agent dispatched via `POST /api/work-items` with `meta.pr_followup` set. Each entry: `{wi_id, title, reason, parent_comment_id}`. See [PR-comment follow-ups](#pr-comment-follow-ups). |
|
|
99
111
|
| `invalidates` | string[] | Optional. List of work-item IDs (e.g. `["W-abc123"]`) whose goals are superseded by this completion. The engine cancels each listed WI that is currently in `pending` or `queued` status, stamping `cancellationReason: "invalidated-by:<source-wi-id>"`. WIs in any other status (dispatched, done, failed, cancelled) are skipped with a warning — they are NOT cancelled. Missing IDs also log a warning and are skipped. Only processed on successful (`effectiveSuccess`) completions. See [Goal invalidation](#goal-invalidation). |
|
|
100
|
-
| `meta.descriptionAudit` | object | Optional, `fix` / `implement` dispatches that push commits. Records the PR description audit + screenshot
|
|
112
|
+
| `meta.descriptionAudit` | object | Optional, `fix` / `implement` dispatches that push commits. Records the PR description audit + screenshot embed/refresh outcome — see [PR description audit](#pr-description-audit). |
|
|
113
|
+
|
|
114
|
+
## Review-learning completion payloads
|
|
115
|
+
|
|
116
|
+
Review and fix agents may report verified, reusable lessons and how previously
|
|
117
|
+
recalled lessons affected the task. These fields are optional. Emit them only
|
|
118
|
+
when the dispatch supplies a trusted finding or comment source identity; never
|
|
119
|
+
derive an identity from reviewer prose.
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"reviewLearnings": [
|
|
124
|
+
{
|
|
125
|
+
"rule": "Validate optional telemetry independently from the code-fix result.",
|
|
126
|
+
"disposition": "accepted-fixed",
|
|
127
|
+
"source": {
|
|
128
|
+
"pr": "github:opg-microsoft/minions#951",
|
|
129
|
+
"sourceKey": "github:review-finding:review-0123456789abcdef"
|
|
130
|
+
},
|
|
131
|
+
"project": "minions-opg",
|
|
132
|
+
"authorAgent": "dallas",
|
|
133
|
+
"applicability": "project-team",
|
|
134
|
+
"files": ["engine/lifecycle.js"],
|
|
135
|
+
"symbols": ["normalizeReviewLearningCompletionPayload"],
|
|
136
|
+
"tags": ["completion-contract"],
|
|
137
|
+
"evidence": [
|
|
138
|
+
"engine/lifecycle.js:5742",
|
|
139
|
+
"test/unit/structured-completion.test.js:158"
|
|
140
|
+
],
|
|
141
|
+
"confidence": 0.92,
|
|
142
|
+
"repeatedOf": "M-review-lesson-1"
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"reviewLearningApplications": [
|
|
146
|
+
{
|
|
147
|
+
"id": "M-review-lesson-1",
|
|
148
|
+
"outcome": "applied",
|
|
149
|
+
"evidence": "engine/lifecycle.js:5742 validates each optional field independently."
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Each `reviewLearnings` entry has this contract:
|
|
156
|
+
|
|
157
|
+
- `rule` is one generalized procedural rule, not a review quote.
|
|
158
|
+
- `disposition` is one of `accepted-fixed`, `satisfied-elsewhere`, `invalid`,
|
|
159
|
+
`stale`, `deferred`, or `out-of-scope-follow-up`. The legacy
|
|
160
|
+
`already-resolved` label is accepted on read and canonicalized to
|
|
161
|
+
`satisfied-elsewhere`.
|
|
162
|
+
- `source.pr` must equal the canonical dispatch PR. `source.sourceKey` must
|
|
163
|
+
equal one of the host-namespaced finding or comment identities trusted by
|
|
164
|
+
that dispatch, such as `github:review-finding:<id>`,
|
|
165
|
+
`github:review-comment:<id>`, or `ado:thread:<thread>:comment:<comment>`.
|
|
166
|
+
- `project` and `authorAgent` must match the dispatch project and tracked PR
|
|
167
|
+
author. `applicability` is `author` or `project-team`.
|
|
168
|
+
- `files`, `symbols`, and `tags` are arrays of repository-relative paths,
|
|
169
|
+
symbol identifiers, and normalized tags. `evidence` is a non-empty array of
|
|
170
|
+
current file/line, test, or commit references. `confidence` is a finite
|
|
171
|
+
number from 0 through 1. `repeatedOf`, when present, is a bounded `M-...`
|
|
172
|
+
lesson ID.
|
|
173
|
+
|
|
174
|
+
Each `reviewLearningApplications` entry contains a bounded `M-...` `id`, an
|
|
175
|
+
`outcome` of `applied`, `considered-not-applicable`, or `contradicted`, and a
|
|
176
|
+
required evidence string. Report the outcome label and observable evidence
|
|
177
|
+
only. Never include reasoning transcripts or chain-of-thought.
|
|
178
|
+
|
|
179
|
+
The engine accepts at most eight learnings (64 KiB total) and at most 32
|
|
180
|
+
applications (16 KiB total). Per learning, `rule` is capped at 1,024 bytes;
|
|
181
|
+
the three facet arrays have at most 20 entries; evidence has at most 20
|
|
182
|
+
entries of 400 bytes; tags are 64 bytes; and memory IDs are 160 bytes.
|
|
183
|
+
Application evidence is capped at 400 bytes. Secret-shaped text is redacted
|
|
184
|
+
before the normalized payload is retained.
|
|
185
|
+
|
|
186
|
+
Malformed `reviewLearnings` and `reviewLearningApplications` fields are
|
|
187
|
+
dropped independently. The engine logs a redacted warning and stamps
|
|
188
|
+
`_reviewLearningDiagnostics` on the work item for operator visibility, while
|
|
189
|
+
an otherwise successful code fix remains successful. A nonce mismatch
|
|
190
|
+
discards the entire completion report. `securityFlags.injectionAttempt: true`
|
|
191
|
+
forces the existing non-retryable failure path and suppresses both review
|
|
192
|
+
learning fields.
|
|
193
|
+
|
|
194
|
+
These fields do not replace `reviewFindingResolution`. An unchanged
|
|
195
|
+
review-feedback fix must still set `noop: true` and prove the exact trusted
|
|
196
|
+
finding through the stricter no-op contract below.
|
|
197
|
+
|
|
198
|
+
When `review-learning-capture` is enabled, the engine processes normalized
|
|
199
|
+
entries only after the completion is otherwise successful and all PR/work-item
|
|
200
|
+
contracts pass. `accepted-fixed` requires verified remote-head advancement or
|
|
201
|
+
an independent approval of the exact current review head.
|
|
202
|
+
`satisfied-elsewhere`, `invalid`, and `stale` require an exact current
|
|
203
|
+
`file:line`, commit, or test reference. Positive entries sharing a source are
|
|
204
|
+
stored as one system-trusted, project-scoped procedural record; invalid/stale
|
|
205
|
+
candidates close, while deferred/follow-up candidates remain non-recallable.
|
|
206
|
+
Repeated-finding telemetry requires an exact symbol or file-plus-rule/tag
|
|
207
|
+
match to a prior lesson and records that lesson ID and match reason. Capture
|
|
208
|
+
warnings are bounded and diagnostic-only: they never reverse a successful fix
|
|
209
|
+
or re-review outcome.
|
|
101
210
|
|
|
102
211
|
## PR description audit
|
|
103
212
|
|
|
@@ -105,10 +214,12 @@ W-mq5l3f2u000i9045. The `fix` and `implement` playbooks inline a `## PR descript
|
|
|
105
214
|
|
|
106
215
|
The audit is best-effort:
|
|
107
216
|
|
|
108
|
-
- Screenshot
|
|
109
|
-
-
|
|
217
|
+
- Screenshot capture requires a runnable dev server (detected via `package.json` scripts named `dev`, `start`, or `serve`) and Playwright MCP. When either is missing or fails, the agent skips the capture without failing the work item.
|
|
218
|
+
- **Proactive embedding (W-mrz1yc79).** For a PR that contains a meaningful **visual/UI change** (dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS), the agent proactively introduces screenshots into the description — it no longer waits for the OPG `Visual evidence capture` CI bot (that bot stays as-is; the in-description embeds are additive). Backend-only, engine-logic, text/prose-only, analysis, and docs changes get no screenshots.
|
|
219
|
+
- **GitHub upload path.** GitHub has no documented REST endpoint for PR-comment image uploads, so the agent publishes the PNGs as assets on a dedicated per-PR prerelease (tag `pr-<num>-visual`, `gh release create/upload … --prerelease`), resolves each asset's `browser_download_url`, and embeds it as ``. This works on private repos, uses a per-command `GH_TOKEN` for the repo owner's account (never `gh auth switch`), and never commits PNGs to the source branch. If the upload fails, the agent skips and records the reason instead of failing.
|
|
220
|
+
- **ADO upload path.** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG bytes, then reference the returned URL — now for newly-introduced screenshots too, not just refreshes.
|
|
110
221
|
- Raw PNGs are saved under `agents/<id>/screenshots/` only. **Screenshots NEVER land in the repo** — adding any code path that `git add`s a PNG is a release-blocker bug.
|
|
111
|
-
- The audit never
|
|
222
|
+
- The audit never rewrites description prose beyond targeted stale edits, never modifies the PR title, never toggles draft state, and never posts a separate PR comment narrating the description change.
|
|
112
223
|
|
|
113
224
|
Record the outcome under `meta.descriptionAudit`. All fields are optional and backward-compatible — older agents that never set them stay valid.
|
|
114
225
|
|
|
@@ -130,9 +241,9 @@ Record the outcome under `meta.descriptionAudit`. All fields are optional and ba
|
|
|
130
241
|
| Field | Type | Notes |
|
|
131
242
|
|---|---|---|
|
|
132
243
|
| `meta.descriptionAudit.ran` | boolean | `true` if the agent executed the audit (whether or not it edited the description). `false` when the audit was suppressed (no commits pushed, no-op completion, `meta.skipDescriptionAudit` set, or the playbook skipped the audit for any reason). Omit `meta.descriptionAudit` entirely when the audit was not even considered. |
|
|
133
|
-
| `meta.descriptionAudit.result` | string | One of: `"no-changes-needed"`, `"description-patched"`, `"screenshots-refreshed"`, `"description-patched+screenshots-refreshed"`, or `"skipped:<reason>"` (e.g. `"skipped:meta-flag"`, `"skipped:no-commits"`, `"skipped:noop"`).
|
|
134
|
-
| `meta.descriptionAudit.oldScreenshots` | string[] | URLs of image refs the agent replaced. Omit or `[]` when no screenshots changed. |
|
|
135
|
-
| `meta.descriptionAudit.newScreenshots` | string[] | URLs of newly uploaded image
|
|
244
|
+
| `meta.descriptionAudit.result` | string | One of: `"no-changes-needed"`, `"description-patched"`, `"screenshots-introduced"`, `"screenshots-refreshed"`, `"description-patched+screenshots-introduced"`, `"description-patched+screenshots-refreshed"`, or `"skipped:<reason>"` (e.g. `"skipped:meta-flag"`, `"skipped:no-commits"`, `"skipped:noop"`). A partial-skip shape like `"screenshots-skipped (dev-server-unavailable)"` is also valid when the dev server, route, Playwright, or upload path is unavailable. |
|
|
245
|
+
| `meta.descriptionAudit.oldScreenshots` | string[] | URLs of image refs the agent replaced when refreshing. Omit or `[]` when no screenshots changed. |
|
|
246
|
+
| `meta.descriptionAudit.newScreenshots` | string[] | URLs of newly uploaded/embedded image assets (release-asset CDN URLs on GitHub, attachment URLs on ADO) — for both newly-introduced and refreshed screenshots. Omit or `[]` when no screenshots changed. |
|
|
136
247
|
| `meta.descriptionAudit.patchedSections` | string[] | Human-readable identifiers of the description sections that changed (e.g. `"feature-bullets"`, `"config-table"`, `"file-list"`, `"line-counts"`, `"ascii-diagram"`, `"screenshots"`). Omit or `[]` when no sections changed. |
|
|
137
248
|
|
|
138
249
|
Dispatchers can suppress the audit entirely by setting `meta.skipDescriptionAudit: true` on the work item — the playbook then renders an explicit "audit suppressed" notice instead of the audit steps. Use this for skill-meta updates, doc-only fixes whose PR description text won't be affected by the diff, and follow-up dispatches that explicitly own the description themselves.
|
|
@@ -174,13 +285,16 @@ Defined in `engine/shared.js` as `FAILURE_CLASS`. Use the canonical hyphenated s
|
|
|
174
285
|
| `build-failure` | Compilation, lint, or test failure introduced by the agent | Retry same agent |
|
|
175
286
|
| `timeout` | Hard runtime timeout or stale-orphan timeout | Retry with fresh session |
|
|
176
287
|
| `empty-output` | Agent produced no meaningful output | Flag for human review |
|
|
288
|
+
| `runtime-truncated-exit` | The runtime process exited `0` in the MIDDLE of a turn: its output holds a tool call that was started and never completed (observed: Copilot exiting right after starting a long `npm test`), and no completion report was written. Detected through the optional adapter hook `hasUnfinishedToolCall`. Distinct from `completion-report-missing`, which means the turn ended normally but the agent skipped the report. | Retry — a fresh attempt normally runs to completion |
|
|
289
|
+
| `runtime-session-stale` | A `--resume`d runtime died because its persisted session is unusable: the backing conversation is gone, or its persisted working directory no longer exists (the engine removed/recycled that worktree). Previously surfaced as an opaque `empty-output`. | Retry — the engine clears the cached session first |
|
|
177
290
|
| `spawn-error` | Process failed to start or crashed immediately | Retry with fresh session |
|
|
178
291
|
| `network-error` | API rate limit, DNS, connectivity | Default retry logic |
|
|
179
292
|
| `out-of-context` | Context window exhausted | Flag for human review |
|
|
180
293
|
| `max-turns` | Claude CLI `error_max_turns` — work in progress | Retry same agent |
|
|
181
294
|
| `completion-nonce-mismatch` | Completion JSON missing or mismatched `nonce` (forged completion). See [Trust boundary](#trust-boundary). | Never retry (untrusted) |
|
|
295
|
+
| `completion-report-missing` | A mutating process exited `0` without a valid required JSON completion report | Retry unless another hard lifecycle contract (such as missing PR) already made the work item terminal |
|
|
182
296
|
| `worktree-preflight` | Pre-spawn worktree validation rejected the dispatch (nested-in-project, drive-root collapse, missing base). See [Pre-spawn preflight vs agent failure](#pre-spawn-preflight-vs-agent-failure). | Never retry |
|
|
183
|
-
| `worktree-dirty` | Reused worktree had uncommitted edits the engine could not auto-heal (#2996) | Never retry this dispatch
|
|
297
|
+
| `worktree-dirty` | Reused worktree had uncommitted edits the engine could not auto-heal (#2996). When the failure came from the self-heal tail (`clean-failed` / `dirty-after-clean` / `recheck-failed`) the engine has already proved there were no unpushed commits, quarantines the tree, and marks the failure retryable. | Never retry this dispatch, EXCEPT the quarantined self-heal cases which retry into a fresh worktree |
|
|
184
298
|
| `worktree-divergent` | Reused worktree's local branch was ahead of origin — unsafe to reset (#2996) | Never retry this dispatch (worktree quarantined) |
|
|
185
299
|
| `worktree-quarantine-env-blocked` | Quarantine rename failed because the OS wouldn't release the worktree dir (Windows EBUSY/EPERM/EACCES) | Retry — re-queued without bumping the per-agent retry counter |
|
|
186
300
|
| `dependency-merge-setup` | Dependency pre-merge plumbing (stash/status/reset) failed before a real file conflict was verified | Retry — fresh worktree can recover |
|
|
@@ -194,6 +308,7 @@ Defined in `engine/shared.js` as `FAILURE_CLASS`. Use the canonical hyphenated s
|
|
|
194
308
|
| `live-checkout-mid-operation` | Operator tree is mid-operation (in-progress merge/rebase/cherry-pick/bisect) or detached HEAD | Never retry — operator must finish/abort first |
|
|
195
309
|
| `live-checkout-blob-fetch` | `git checkout` failed materializing the tree on a blobless/GVFS-partial clone — deterministic, not transient | Never retry — operator hydrates the branch with their own credentials |
|
|
196
310
|
| `live-checkout-worktree-conflict` | Target branch is already checked out in a second worktree elsewhere — structural, doesn't clear on retry | Never retry — operator removes/reassigns the other worktree |
|
|
311
|
+
| `live-checkout-stale-base` | Spawn-time defense found local `mainRef` ahead of `origin/<mainRef>`; forking would inherit committed contamination | Never retry — operator reconciles the local base first |
|
|
197
312
|
| `live-checkout-wrong-base` | New-branch fork requested but operator HEAD is on an unrelated branch, not the project base | Never retry — operator checks out `mainRef` first (or enable `liveCheckoutAutoBaseRepair`) |
|
|
198
313
|
| `invalid-workdir` | Dispatch carried a `meta.workdir` override that failed validation (absolute path, `..` segment, escape, etc.) | Never retry until the WI's `meta.workdir` is fixed |
|
|
199
314
|
| `model-unavailable` | Requested model returned `overloaded_error` / 503 / service unavailable | Retry — engine swaps in the runtime-appropriate fallback model |
|
|
@@ -204,6 +319,7 @@ Defined in `engine/shared.js` as `FAILURE_CLASS`. Use the canonical hyphenated s
|
|
|
204
319
|
| `output-truncated` | Agent streamed more stdout than the engine's hard capture cap before the terminal `result` event arrived | Never retry — agent must reduce output volume or split the task |
|
|
205
320
|
| `verify-missing-pr` | A verify WI exited `done` but no PR was attached | Retry — agent may have phantom-crashed before pushing |
|
|
206
321
|
| `project_not_found` | A work item's `project` field names a project that isn't configured | Never retry until the WI's `project` field or config is fixed |
|
|
322
|
+
| `pre-dispatch-eval-stuck` | Legacy persisted classification for unchanged descriptions rejected repeatedly; migration 026 converts these to pending `_preDispatchEval.exhausted` state | Never retry as an execution failure — edit the description |
|
|
207
323
|
| `unknown` | Unclassified failure | Default retry logic |
|
|
208
324
|
|
|
209
325
|
Use `"N/A"` when `status` is `success` or `partial` without a failure.
|
|
@@ -256,13 +372,13 @@ If the live PR branch did not advance, the completion must set `noop: true` and
|
|
|
256
372
|
{
|
|
257
373
|
"reviewFindingResolution": {
|
|
258
374
|
"findingId": "review-0123456789abcdef",
|
|
259
|
-
"disposition": "
|
|
375
|
+
"disposition": "satisfied-elsewhere",
|
|
260
376
|
"currentCodeEvidence": "engine/lifecycle.js:4600 already enforces the condition; test/unit/example.test.js covers it."
|
|
261
377
|
}
|
|
262
378
|
}
|
|
263
379
|
```
|
|
264
380
|
|
|
265
|
-
The `findingId` is injected into the fix playbook from trusted `minionsReview` provenance. `disposition` is `
|
|
381
|
+
The `findingId` is injected into the fix playbook from trusted `minionsReview` provenance. `disposition` is `satisfied-elsewhere` or `invalid`; legacy `already-resolved` is accepted and canonicalized to `satisfied-elsewhere`. `currentCodeEvidence` must cite a current `file:line` or commit. An identity-only no-op is retried and does not increment `_noOpFixes`.
|
|
266
382
|
|
|
267
383
|
## PR-comment follow-ups
|
|
268
384
|
|
package/docs/constants.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Constants — No Magic Strings
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cross-cutting status / type / condition values are defined in [`engine/shared.js`](../engine/shared.js). Engine and dashboard code should use these constants instead of raw strings; source-inspection tests enforce the load-bearing comparisons.
|
|
4
4
|
|
|
5
5
|
```js
|
|
6
6
|
WI_STATUS = { PENDING, DISPATCHED, DONE, FAILED, PAUSED, QUEUED, DECOMPOSED, CANCELLED }
|
|
7
7
|
DONE_STATUSES = Set([WI_STATUS.DONE, 'in-pr', 'implemented', 'complete']) // legacy aliases on read only
|
|
8
|
+
PLAN_TERMINAL_STATUSES = Set([...DONE_STATUSES, WI_STATUS.FAILED, WI_STATUS.CANCELLED])
|
|
8
9
|
WORK_TYPE = { IMPLEMENT, IMPLEMENT_LARGE, FIX, REVIEW, VERIFY, PLAN, PLAN_TO_PRD,
|
|
9
10
|
DECOMPOSE, MEETING, EXPLORE, ASK, TEST, DOCS, SETUP, BUILD_FIX_COMPLEX }
|
|
10
11
|
PLAN_STATUS = { ACTIVE, AWAITING_APPROVAL, APPROVED, PAUSED, REJECTED, COMPLETED, REVISION_REQUESTED }
|
|
@@ -19,14 +20,25 @@ WATCH_CONDITION = { MERGED, BUILD_FAIL, BUILD_PASS, COMPLETED, FAILED, STATUS_CH
|
|
|
19
20
|
STAGE_ADVANCED, STUCK_IN_STAGE }
|
|
20
21
|
WATCH_ABSOLUTE_CONDITIONS = Set([MERGED, BUILD_FAIL, BUILD_PASS, COMPLETED, FAILED, CONCLUDED, APPROVED,
|
|
21
22
|
REJECTED, READY_FOR_MERGE, RETRY_LIMIT_REACHED, ALL_ITEMS_DONE, ITEM_FAILED_N_TIMES]) // fire-once
|
|
23
|
+
WATCH_TARGET_TYPE = { PR, WORK_ITEM, MEETING, PLAN, SCHEDULE, PIPELINE, DISPATCH, AGENT } // built-ins; watches.d/*.js may register more
|
|
24
|
+
WATCH_ACTION_TYPE = { NOTIFY, DISPATCH_WORK_ITEM, RUN_SKILL, WEBHOOK, MINIONS_API,
|
|
25
|
+
CANCEL_WORK_ITEM, TRIGGER_PIPELINE, ARCHIVE_PLAN, RESUME_PLAN, CC_TRIAGE }
|
|
26
|
+
BUILD_STATUS = { PASSING, FAILING, RUNNING, NONE }
|
|
27
|
+
REVIEW_STATUS = { APPROVED, CHANGES_REQUESTED, WAITING, PENDING } // APPROVED is permanent terminal — never downgrade
|
|
28
|
+
AGENT_STATUS = { SPAWNING, WORKTREE_SETUP, READY, RUNNING, FINISHED, FAILED, TRUST_BLOCKED, TIMED_OUT }
|
|
29
|
+
MEETING_STATUS = { INVESTIGATING, DEBATING, CONCLUDING, COMPLETED, ARCHIVED }
|
|
30
|
+
PIPELINE_STATUS = { PENDING, RUNNING, COMPLETED, FAILED, PAUSED, WAITING_HUMAN, STOPPED }
|
|
31
|
+
STAGE_TYPE = { TASK, MEETING, PLAN, API, MERGE_PRS, SCHEDULE, WAIT, PARALLEL, CONDITION } // pipelines/*.json stage kinds
|
|
32
|
+
CHECKOUT_MODES = { WORKTREE, LIVE } // project.checkoutMode; see docs/live-checkout-mode.md
|
|
33
|
+
FAILURE_CLASS = { ... } // dispatch failure taxonomy — full enum in docs/completion-reports.md
|
|
22
34
|
```
|
|
23
35
|
|
|
24
36
|
## Engine defaults
|
|
25
37
|
|
|
26
|
-
Retry/timeout limits, sweep cadences, fleet ceilings, and managed-spawn caps live in `ENGINE_DEFAULTS` (also in `engine/shared.js`). Read defaults from there rather than re-declaring
|
|
38
|
+
Retry/timeout limits, sweep cadences, fleet ceilings, and managed-spawn caps live in `ENGINE_DEFAULTS` (also in `engine/shared.js`). Read defaults from there rather than re-declaring. Some keys resolve a `config.engine.*` override through a helper (`resolveAgentMaxBudget`, etc.); others are source-only, so verify the call site before documenting a Settings/config knob.
|
|
27
39
|
|
|
28
40
|
## Invariants
|
|
29
41
|
|
|
30
42
|
- **Write only `WI_STATUS.DONE`.** Legacy aliases (`in-pr`, `implemented`, `complete`) are accepted on read for backward compat but never written. `updateWorkItemStatus()` validates writes against `WI_STATUS`.
|
|
31
|
-
-
|
|
43
|
+
- **SQL store mutators for runtime state.** `mutateWorkItems`, `mutatePullRequests`, and `mutateDispatch` delegate to SQL-backed store modules (not JSON-locked wrappers). `mutateJsonFileLocked()` is reserved for intentionally file-backed RMW — configuration, definitions, and coordination sidecars. Route all runtime-state RMW through the appropriate store mutator — see [`CLAUDE.md`](../CLAUDE.md) → **Concurrency**.
|
|
32
44
|
- **No string comparisons.** `pr.status === 'active'` ⇒ `pr.status === PR_STATUS.ACTIVE`. Source-inspection tests grep for the constant form.
|
|
@@ -10,12 +10,12 @@ A **1:1 port is the wrong goal.** Constellation's telemetry is built for a *host
|
|
|
10
10
|
multi-tenant, server-side fleet*: PostgreSQL storage, WebSocket ingestion,
|
|
11
11
|
per-constellation/per-device tenancy, and a bearer-authed global-admin dashboard.
|
|
12
12
|
Minions is the structural opposite — *single-machine, local-first, zero-deps-beyond-Node,
|
|
13
|
-
|
|
13
|
+
embedded-SQLite state (`engine/state.db` via built-in `node:sqlite`), loopback dashboard*.
|
|
14
14
|
|
|
15
15
|
But the **valuable, portable subset is very feasible**, and Minions already has ~60% of it.
|
|
16
16
|
The realistic target is a **local-first usage/analytics layer**: a typed append-only event
|
|
17
17
|
log + a retention/rollup discipline + a dedicated dashboard "Usage" page, optionally a
|
|
18
|
-
`/metrics` Prometheus endpoint. **No database, no new runtime dependencies, no new network
|
|
18
|
+
`/metrics` Prometheus endpoint. **No server database, no new runtime dependencies, no new network
|
|
19
19
|
egress** (preserves the "nothing leaves the machine" property — Minions' own code has no
|
|
20
20
|
external telemetry today).
|
|
21
21
|
|