@yemi33/minions 0.1.2378 → 0.1.2380
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 +19 -9
- package/dashboard/js/refresh.js +2 -3
- package/dashboard/js/render-prd.js +1 -1
- package/dashboard/js/render-work-items.js +13 -6
- package/dashboard.js +393 -721
- package/docs/README.md +1 -0
- package/docs/architecture-review-2026-07-09.md +2 -4
- package/docs/auto-discovery.md +36 -49
- package/docs/blog-first-successful-dispatch.md +1 -1
- package/docs/branch-derivation.md +2 -2
- package/docs/command-center.md +1 -1
- package/docs/completion-reports.md +14 -4
- package/docs/constellation-bridge.md +59 -10
- package/docs/constellation-style-telemetry.md +6 -6
- package/docs/cooldown-merge-semantics.md +4 -0
- package/docs/copilot-cli-schema.md +3 -3
- package/docs/cross-repo-plans.md +17 -17
- package/docs/deprecated.json +2 -2
- package/docs/design-inbox-entries-schema.md +31 -39
- package/docs/design-state-storage.md +1 -1
- package/docs/documentation-audit-2026-07-09.md +2 -2
- package/docs/engine-restart.md +20 -8
- package/docs/harness-mode.md +1 -1
- package/docs/managed-spawn.md +4 -4
- package/docs/onboarding.md +1 -2
- package/docs/pr-comment-followup.md +3 -3
- package/docs/pr-review-fix-loop.md +1 -1
- package/docs/proposals/repo-pool-for-live-checkout.md +1 -2
- package/docs/qa-runbook-lifecycle.md +4 -4
- package/docs/qa-runbooks.md +2 -2
- package/docs/rfc-completion-json.md +4 -1
- package/docs/runtime-adapters.md +1 -1
- package/docs/self-improvement.md +4 -5
- package/docs/shared-lifecycle-module-map.md +3 -1
- package/docs/slim-ux/architecture-suggestions.md +5 -6
- package/docs/slim-ux/concepts.md +23 -25
- package/docs/watches.md +7 -7
- package/docs/workspace-manifests.md +1 -1
- package/docs/worktree-lifecycle.md +1 -1
- package/engine/abandoned-pr-reconciliation.js +4 -5
- package/engine/acp-transport.js +49 -8
- package/engine/ado-status.js +5 -5
- package/engine/ado.js +20 -25
- package/engine/agent-worker-pool.js +124 -15
- package/engine/bridge.js +260 -5
- package/engine/cleanup.js +48 -131
- package/engine/cli.js +125 -83
- package/engine/cooldown.js +9 -16
- package/engine/db/index.js +22 -9
- package/engine/db/migrations/009-qa.js +1 -1
- package/engine/db/migrations/020-qa-session-scopes.js +23 -0
- package/engine/db/migrations/021-archived-work-items.js +72 -0
- package/engine/db/migrations/022-global-cc-session.js +31 -0
- package/engine/db/migrations/023-engine-state.js +30 -0
- package/engine/db/migrations/024-prd-ghost-collisions.js +53 -0
- package/engine/db/migrations/025-malformed-work-item-phantoms.js +33 -0
- package/engine/dispatch-store.js +2 -7
- package/engine/dispatch.js +34 -41
- package/engine/github.js +20 -27
- package/engine/lifecycle.js +221 -283
- package/engine/llm.js +1 -1
- package/engine/logs-store.js +2 -2
- package/engine/managed-spawn.js +2 -23
- package/engine/meeting.js +6 -6
- package/engine/metrics-store.js +2 -2
- package/engine/note-link-backfill.js +6 -11
- package/engine/pipeline.js +18 -36
- package/engine/playbook.js +1 -1
- package/engine/pooled-agent-process.js +46 -26
- package/engine/prd-store.js +73 -54
- package/engine/preflight.js +2 -5
- package/engine/projects.js +15 -62
- package/engine/pull-requests-store.js +0 -17
- package/engine/qa-runbooks.js +2 -2
- package/engine/qa-runs.js +1 -8
- package/engine/qa-sessions.js +41 -64
- package/engine/queries.js +120 -219
- package/engine/routing.js +3 -5
- package/engine/scheduler.js +0 -4
- package/engine/shared-branch-pr-reconcile.js +2 -3
- package/engine/shared.js +132 -637
- package/engine/small-state-store.js +89 -10
- package/engine/state-operations.js +16 -4
- package/engine/stdio-timestamps.js +1 -1
- package/engine/timeout.js +5 -12
- package/engine/watch-actions.js +20 -22
- package/engine/watches-store.js +1 -1
- package/engine/watches.js +6 -10
- package/engine/work-item-validation.js +52 -0
- package/engine/work-items-store.js +127 -29
- package/engine/worktree-gc.js +2 -2
- package/engine/worktree-pool.js +8 -18
- package/engine.js +167 -349
- package/minions.js +2 -2
- package/package.json +1 -1
- package/playbooks/plan-to-prd.md +2 -2
- package/playbooks/shared-rules.md +3 -3
- package/playbooks/templates/followup-dispatch.md +1 -1
- package/playbooks/verify.md +1 -1
- package/prompts/cc-system.md +2 -2
package/bin/minions.js
CHANGED
|
@@ -1404,9 +1404,21 @@ ${fs.existsSync(path.join(PKG_ROOT, '.git')) ? `
|
|
|
1404
1404
|
// PowerShell is unavailable, the engine is hung, or its cmdline doesn't match.
|
|
1405
1405
|
const oldEnginePid = readEnginePid(MINIONS_HOME);
|
|
1406
1406
|
try { execSync(`node "${path.join(MINIONS_HOME, 'engine.js')}" stop`, { stdio: 'ignore', cwd: MINIONS_HOME, timeout: 10000, windowsHide: true }); } catch {}
|
|
1407
|
-
//
|
|
1408
|
-
//
|
|
1409
|
-
|
|
1407
|
+
// Give the engine's graceful handler time to drain non-reattachable pooled
|
|
1408
|
+
// leases. Detached cold agents are not part of that drain and remain alive
|
|
1409
|
+
// for normal PID-file reattachment by the replacement engine.
|
|
1410
|
+
const shutdownTimeout = (() => {
|
|
1411
|
+
try {
|
|
1412
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(MINIONS_HOME, 'config.json'), 'utf8'));
|
|
1413
|
+
return Number(cfg?.engine?.shutdownTimeout) || shared.ENGINE_DEFAULTS.shutdownTimeout;
|
|
1414
|
+
} catch { return shared.ENGINE_DEFAULTS.shutdownTimeout; }
|
|
1415
|
+
})();
|
|
1416
|
+
const gracefulEngineStop = waitForPidDeath(oldEnginePid, shutdownTimeout + 5000);
|
|
1417
|
+
if (!gracefulEngineStop.ok) {
|
|
1418
|
+
// Fallback for a hung engine. Kill only the engine PID, never its detached
|
|
1419
|
+
// cold-agent children; pooled leases have already exceeded their drain budget.
|
|
1420
|
+
killPidOnly(oldEnginePid);
|
|
1421
|
+
}
|
|
1410
1422
|
killByPort(restartResolved.port);
|
|
1411
1423
|
killMinionsProcesses(['engine.js', 'dashboard.js', 'supervisor.js']);
|
|
1412
1424
|
// Confirm the OS finished the asynchronous termination before we spawn new
|
|
@@ -1491,15 +1503,13 @@ ${fs.existsSync(path.join(PKG_ROOT, '.git')) ? `
|
|
|
1491
1503
|
const engineDir = path.join(MINIONS_HOME, 'engine');
|
|
1492
1504
|
|
|
1493
1505
|
// Engine state
|
|
1494
|
-
|
|
1506
|
+
require(path.join(PKG_ROOT, 'engine', 'db')).cleanupRetiredJsonFiles(MINIONS_HOME);
|
|
1507
|
+
for (const f of ['state.db', 'state.db-wal', 'state.db-shm', 'control.json', 'kb-checkpoint.json']) {
|
|
1508
|
+
rm(path.join(engineDir, f));
|
|
1509
|
+
}
|
|
1495
1510
|
glob(engineDir, /^pid-.*\.pid$/).forEach(rm);
|
|
1496
1511
|
rmDir(path.join(engineDir, 'tmp'));
|
|
1497
1512
|
|
|
1498
|
-
// Work items + PRs
|
|
1499
|
-
rm(path.join(MINIONS_HOME, 'work-items.json'));
|
|
1500
|
-
rm(path.join(MINIONS_HOME, 'work-items-archive.json'));
|
|
1501
|
-
rm(path.join(MINIONS_HOME, 'pull-requests.json'));
|
|
1502
|
-
|
|
1503
1513
|
// Plans + PRDs + Pipelines + Meetings
|
|
1504
1514
|
rmDir(path.join(MINIONS_HOME, 'plans'));
|
|
1505
1515
|
rmDir(path.join(MINIONS_HOME, 'prd'));
|
package/dashboard/js/refresh.js
CHANGED
|
@@ -151,9 +151,8 @@ const RENDER_VERSIONS = {
|
|
|
151
151
|
dispatch: 2,
|
|
152
152
|
engineLog: 2,
|
|
153
153
|
metrics: 1,
|
|
154
|
-
// Bumped
|
|
155
|
-
|
|
156
|
-
workItems: 8,
|
|
154
|
+
// Bumped 8->9: row actions now preserve work-item source scope when IDs collide.
|
|
155
|
+
workItems: 9,
|
|
157
156
|
skills: 1,
|
|
158
157
|
commands: 1,
|
|
159
158
|
mcpServers: 1,
|
|
@@ -855,7 +855,7 @@ async function prdItemEdit(source, itemId) {
|
|
|
855
855
|
|
|
856
856
|
completionHtml = '<div style="background:var(--surface);border:1px solid var(--border);border-left:3px solid ' + statusColor + ';border-radius:4px;padding:10px 12px;margin-bottom:12px">' +
|
|
857
857
|
'<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">' +
|
|
858
|
-
(wi ? '<a href="#" onclick="event.preventDefault();event.stopPropagation();openWorkItemDetail(\'' + escHtml(wi.id) + '\')" title="Open ' + escHtml(wi.id) + ' detail" style="font-size:var(--text-base);font-weight:700;color:' + statusColor + ';text-decoration:none;cursor:pointer" onmouseover="this.style.textDecoration=\'underline\'" onmouseout="this.style.textDecoration=\'none\'">' + statusLabel + ' →</a>' : '<span style="font-size:var(--text-base);font-weight:700;color:' + statusColor + '">' + statusLabel + '</span>') +
|
|
858
|
+
(wi ? '<a href="#" onclick="event.preventDefault();event.stopPropagation();openWorkItemDetail(\'' + escHtml(wi.id) + '\',\'' + escHtml(wi._source || '') + '\')" title="Open ' + escHtml(wi.id) + ' detail" style="font-size:var(--text-base);font-weight:700;color:' + statusColor + ';text-decoration:none;cursor:pointer" onmouseover="this.style.textDecoration=\'underline\'" onmouseout="this.style.textDecoration=\'none\'">' + statusLabel + ' →</a>' : '<span style="font-size:var(--text-base);font-weight:700;color:' + statusColor + '">' + statusLabel + '</span>') +
|
|
859
859
|
typePillHtml +
|
|
860
860
|
(agent ? '<span style="font-size:var(--text-base);color:var(--muted)">by ' + escHtml(agent) + '</span>' : '') +
|
|
861
861
|
(completedAt ? '<span style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(completedAt.slice(0, 16).replace('T', ' ')) + '</span>' : '') +
|
|
@@ -192,7 +192,7 @@ function wiRow(item) {
|
|
|
192
192
|
var prLabel = prNumMatch ? ('PR #' + prNumMatch[1]) : 'parent PR';
|
|
193
193
|
followupChip = ' <a class="pr-badge draft" style="font-size:var(--text-xs);text-decoration:none" target="_blank" rel="noopener" href="' + escapeHtml(prFollowup.parent_pr_url) + '" title="Follow-up dispatched from ' + escapeHtml(prRef) + (prFollowup.parent_comment_author ? ' by ' + escapeHtml(prFollowup.parent_comment_author) : '') + '" onclick="event.stopPropagation()">↩ from ' + escapeHtml(prLabel) + '</a>';
|
|
194
194
|
}
|
|
195
|
-
return '<tr data-wi-id="' + escapeHtml(item.id) + '" style="cursor:pointer" onclick="if(shouldIgnoreSelectionClick(event))return;openWorkItemDetail(\'' + escapeHtml(item.id) + '\')">' +
|
|
195
|
+
return '<tr data-wi-id="' + escapeHtml(item.id) + '" style="cursor:pointer" onclick="if(shouldIgnoreSelectionClick(event))return;openWorkItemDetail(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')">' +
|
|
196
196
|
'<td style="min-width:280px;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escapeHtml((item.title || '').slice(0, 200)) + '">' + escapeHtml(item.title || '') + followupChip + '</td>' +
|
|
197
197
|
'<td><span style="font-size:var(--text-sm);color:var(--muted)">' + escapeHtml(item._source || '') + '</span>' +
|
|
198
198
|
(item.scope === 'fan-out' ? ' <span class="pr-badge ' + (item.status === 'done' || item.status === 'failed' ? 'draft' : 'building') + '" style="font-size:var(--text-xs)">fan-out</span>' : '') + '</td>' +
|
|
@@ -312,7 +312,8 @@ function renderWorkItems(items, opts) {
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
async function editWorkItem(id, source) {
|
|
315
|
-
|
|
315
|
+
source = source || '';
|
|
316
|
+
const cached = allWorkItems.find(i => i.id === id && (!source || i._source === source));
|
|
316
317
|
if (!cached) return;
|
|
317
318
|
// Hydrate the full record before rendering the form. The bulk
|
|
318
319
|
// /api/work-items list endpoint truncates `description` and replaces
|
|
@@ -331,7 +332,7 @@ async function editWorkItem(id, source) {
|
|
|
331
332
|
(cached.referencesCount > 0 && !Array.isArray(cached.references));
|
|
332
333
|
if (needsHydration) {
|
|
333
334
|
try {
|
|
334
|
-
const r = await fetch('/api/work-items/' + encodeURIComponent(id));
|
|
335
|
+
const r = await fetch('/api/work-items/' + encodeURIComponent(id) + '?source=' + encodeURIComponent(source));
|
|
335
336
|
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
336
337
|
const data = await r.json();
|
|
337
338
|
const full = data && data.item;
|
|
@@ -972,9 +973,15 @@ function _wiRenderDetail(item) {
|
|
|
972
973
|
return html;
|
|
973
974
|
}
|
|
974
975
|
|
|
975
|
-
function openWorkItemDetail(id) {
|
|
976
|
+
function openWorkItemDetail(id, source) {
|
|
976
977
|
if (window.getSelection && window.getSelection().toString().length > 0) return;
|
|
977
|
-
|
|
978
|
+
source = source || '';
|
|
979
|
+
const matches = allWorkItems.filter(i => i.id === id && (!source || i._source === source));
|
|
980
|
+
if (!source && matches.length > 1) {
|
|
981
|
+
alert('Multiple work items share this ID. Open it from the Work Items page to select the project.');
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
const cached = matches[0];
|
|
978
985
|
if (!cached) return;
|
|
979
986
|
|
|
980
987
|
// Render the modal immediately from the cached (slim) record so the click
|
|
@@ -999,7 +1006,7 @@ function openWorkItemDetail(id) {
|
|
|
999
1006
|
|
|
1000
1007
|
if (!needsHydration) return;
|
|
1001
1008
|
|
|
1002
|
-
fetch('/api/work-items/' + encodeURIComponent(id))
|
|
1009
|
+
fetch('/api/work-items/' + encodeURIComponent(id) + '?source=' + encodeURIComponent(source))
|
|
1003
1010
|
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
|
|
1004
1011
|
.then(function(data) {
|
|
1005
1012
|
// Guard against modal navigation away from this WI during the fetch.
|