@yemi33/minions 0.1.152 → 0.1.154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dashboard/js/command-center.js +3 -5
- package/dashboard/js/modal-qa.js +3 -45
- package/dashboard/js/modal.js +0 -2
- package/dashboard/js/refresh.js +44 -0
- package/dashboard/js/render-inbox.js +0 -1
- package/dashboard/js/render-kb.js +0 -1
- package/dashboard/js/render-plans.js +2 -44
- package/dashboard/js/render-prd.js +10 -12
- package/dashboard/js/render-work-items.js +42 -8
- package/dashboard/styles.css +4 -2
- package/dashboard.html +8 -103
- package/dashboard.js +2 -144
- package/docs/deprecated.json +1 -83
- package/engine/lifecycle.js +72 -57
- package/engine/playbook.js +1 -1
- package/engine/queries.js +2 -4
- package/engine.js +5 -5
- package/package.json +1 -1
package/dashboard.html
CHANGED
|
@@ -178,8 +178,6 @@
|
|
|
178
178
|
.prd-items-list { display: flex; flex-direction: column; gap: 3px; max-height: 400px; overflow-y: auto; padding: 0 8px; }
|
|
179
179
|
.prd-item-row { display: flex; align-items: center; gap: 8px; padding: 4px 8px; border-radius: var(--radius-sm); font-size: var(--text-base); background: var(--surface2); border: 1px solid var(--border); border-left: 3px solid var(--border); }
|
|
180
180
|
.prd-item-row.st-done { border-left-color: var(--green); }
|
|
181
|
-
.prd-item-row.st-implemented { border-left-color: var(--green); } /* legacy alias */
|
|
182
|
-
.prd-item-row.st-in-pr { border-left-color: var(--green); } /* backward compat: treated as done */
|
|
183
181
|
.prd-item-row.st-in-progress { border-left-color: var(--yellow); animation: prdWipPulse 2s infinite; }
|
|
184
182
|
@keyframes prdWipPulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(210,153,34,0); } 50% { box-shadow: 0 0 0 4px rgba(210,153,34,0.2); } }
|
|
185
183
|
.prd-item-row.st-failed { border-left-color: var(--red); }
|
|
@@ -1171,7 +1169,7 @@ function renderPrdProgress(prog) {
|
|
|
1171
1169
|
// Compute progress from active (non-archived) items only
|
|
1172
1170
|
const activeItems = (prog.items || []).filter(i => !i._archived);
|
|
1173
1171
|
if (activeItems.length > 0) {
|
|
1174
|
-
const activeDone = activeItems.filter(i => i.status === 'done'
|
|
1172
|
+
const activeDone = activeItems.filter(i => i.status === 'done').length;
|
|
1175
1173
|
countEl.textContent = Math.round((activeDone / activeItems.length) * 100) + '%';
|
|
1176
1174
|
} else {
|
|
1177
1175
|
countEl.textContent = '—';
|
|
@@ -1180,7 +1178,7 @@ function renderPrdProgress(prog) {
|
|
|
1180
1178
|
function renderGroupStats(items) {
|
|
1181
1179
|
const total = items.length;
|
|
1182
1180
|
if (total === 0) return '';
|
|
1183
|
-
const done = items.filter(i => i.status === 'done'
|
|
1181
|
+
const done = items.filter(i => i.status === 'done').length;
|
|
1184
1182
|
const inProgress = items.filter(i => i.status === 'in-progress').length;
|
|
1185
1183
|
const failed = items.filter(i => i.status === 'failed').length;
|
|
1186
1184
|
const paused = items.filter(i => i.status === 'paused').length;
|
|
@@ -1210,13 +1208,11 @@ function renderPrdProgress(prog) {
|
|
|
1210
1208
|
const statusBadge = (s) => {
|
|
1211
1209
|
const styles = {
|
|
1212
1210
|
'done': 'background:rgba(63,185,80,0.15);color:var(--green)',
|
|
1213
|
-
'implemented': 'background:rgba(63,185,80,0.15);color:var(--green)', /* legacy alias */
|
|
1214
|
-
'in-pr': 'background:rgba(63,185,80,0.15);color:var(--green)', /* backward compat: displayed as done */
|
|
1215
1211
|
'in-progress': 'background:rgba(210,153,34,0.15);color:var(--yellow);animation:wipPulse 1.5s infinite',
|
|
1216
1212
|
'failed': 'background:rgba(248,81,73,0.15);color:var(--red)',
|
|
1217
1213
|
'paused': 'background:rgba(139,148,158,0.15);color:var(--muted)',
|
|
1218
1214
|
};
|
|
1219
|
-
const labels = { 'done': 'DONE', '
|
|
1215
|
+
const labels = { 'done': 'DONE', 'in-progress': 'WIP', 'failed': 'FAIL', 'paused': 'PAUSED', 'missing': '—' };
|
|
1220
1216
|
const style = styles[s] || 'background:var(--surface);color:var(--muted)';
|
|
1221
1217
|
const label = labels[s] || '—';
|
|
1222
1218
|
return '<span style="font-size:9px;font-weight:700;padding:2px 6px;border-radius:3px;letter-spacing:0.5px;white-space:nowrap;' + style + '">' + label + '</span>';
|
|
@@ -1295,7 +1291,7 @@ function renderPrdProgress(prog) {
|
|
|
1295
1291
|
const timings = prog.planTimings || {};
|
|
1296
1292
|
|
|
1297
1293
|
const renderGroupHeader = (g) => {
|
|
1298
|
-
const done = g.items.filter(i => i.status === 'done'
|
|
1294
|
+
const done = g.items.filter(i => i.status === 'done').length;
|
|
1299
1295
|
const wip = g.items.filter(i => i.status === 'in-progress' || i.status === 'dispatched').length;
|
|
1300
1296
|
const summary = (g.summary || '').replace(/^Convert plan to PRD:\s*/i, '').slice(0, 80);
|
|
1301
1297
|
const isAwaitingApproval = g.planStatus === 'awaiting-approval';
|
|
@@ -1394,7 +1390,7 @@ function renderPrdProgress(prog) {
|
|
|
1394
1390
|
});
|
|
1395
1391
|
|
|
1396
1392
|
const statusColor = (s) => {
|
|
1397
|
-
if (s === 'done'
|
|
1393
|
+
if (s === 'done') return 'var(--green)';
|
|
1398
1394
|
if (s === 'in-progress') return 'var(--yellow)';
|
|
1399
1395
|
if (s === 'failed') return 'var(--red)';
|
|
1400
1396
|
if (s === 'paused') return 'var(--muted)';
|
|
@@ -1565,7 +1561,7 @@ function openArchivedPrdModal() {
|
|
|
1565
1561
|
// Picker: list archived plans, click to expand
|
|
1566
1562
|
html = '<div style="margin-bottom:12px;font-size:12px;color:var(--muted)">Select an archived PRD to view:</div>';
|
|
1567
1563
|
html += groups.map((g, i) => {
|
|
1568
|
-
const done = g.items.filter(it => it.status === 'done'
|
|
1564
|
+
const done = g.items.filter(it => it.status === 'done').length;
|
|
1569
1565
|
const failed = g.items.filter(it => it.status === 'failed').length;
|
|
1570
1566
|
return '<div class="plan-card" style="cursor:pointer;margin-bottom:8px" onclick="showArchivedPrdDetail(' + i + ')">' +
|
|
1571
1567
|
'<div class="plan-card-title" style="font-size:13px">' + escHtml(g.summary || g.file) + '</div>' +
|
|
@@ -1661,7 +1657,7 @@ async function prdItemEdit(source, itemId) {
|
|
|
1661
1657
|
|
|
1662
1658
|
// Build completion summary section
|
|
1663
1659
|
let completionHtml = '';
|
|
1664
|
-
const isDone = item.status === 'done'
|
|
1660
|
+
const isDone = item.status === 'done';
|
|
1665
1661
|
const isFailed = item.status === 'failed';
|
|
1666
1662
|
const isActive = item.status === 'in-progress' || item.status === 'dispatched';
|
|
1667
1663
|
|
|
@@ -1931,7 +1927,6 @@ function openNotesModal() {
|
|
|
1931
1927
|
_modalEditable = 'notes.md';
|
|
1932
1928
|
_modalFilePath = 'notes.md'; showModalQa();
|
|
1933
1929
|
document.getElementById('modal-edit-btn').style.display = '';
|
|
1934
|
-
// steer btn removed — unified send
|
|
1935
1930
|
document.getElementById('modal').classList.add('open');
|
|
1936
1931
|
}
|
|
1937
1932
|
|
|
@@ -2130,8 +2125,6 @@ function closeModal() {
|
|
|
2130
2125
|
// Clear edit/steer state
|
|
2131
2126
|
_modalEditable = null;
|
|
2132
2127
|
_modalFilePath = null;
|
|
2133
|
-
_modalOriginalPlan = null;
|
|
2134
|
-
// steer btn removed — unified send
|
|
2135
2128
|
const body = document.getElementById('modal-body');
|
|
2136
2129
|
body.contentEditable = 'false';
|
|
2137
2130
|
body.style.border = '';
|
|
@@ -2194,7 +2187,7 @@ function openArchive(i) {
|
|
|
2194
2187
|
html += '<div class="archive-feature">' +
|
|
2195
2188
|
'<span class="feat-id">' + escHtml(f.id) + '</span> ' +
|
|
2196
2189
|
'<span class="prd-item-priority ' + pClass + '">' + escHtml(f.priority || '') + '</span>' +
|
|
2197
|
-
(f.status ? ' <span class="pr-badge ' + (f.status === '
|
|
2190
|
+
(f.status ? ' <span class="pr-badge ' + (f.status === 'done' ? 'approved' : 'draft') + '" style="font-size:9px">' + escHtml(f.status) + '</span>' : '') +
|
|
2198
2191
|
'<div class="feat-name">' + escHtml(f.name) + '</div>' +
|
|
2199
2192
|
'<div class="feat-desc">' + escHtml(f.description || '') + '</div>' +
|
|
2200
2193
|
(f.rationale ? '<div class="feat-desc" style="margin-top:4px;color:var(--yellow)">Rationale: ' + escHtml(f.rationale) + '</div>' : '') +
|
|
@@ -3539,7 +3532,6 @@ async function cmdSubmit() {
|
|
|
3539
3532
|
|
|
3540
3533
|
let _modalDocContext = { title: '', content: '', selection: '' };
|
|
3541
3534
|
let _modalFilePath = null; // file path for steering (null = read-only Q&A only)
|
|
3542
|
-
let _modalOriginalPlan = null; // tracks original plan file when editing a forked version
|
|
3543
3535
|
|
|
3544
3536
|
// ─── Notification Badges ──────────────────────────────────────────────────────
|
|
3545
3537
|
// Show a red dot on a card/button when a background response arrives
|
|
@@ -4131,91 +4123,6 @@ async function planApprove(file) {
|
|
|
4131
4123
|
} catch (e) { showToast('cmd-toast', 'Error: ' + e.message, false); }
|
|
4132
4124
|
}
|
|
4133
4125
|
|
|
4134
|
-
// Disable all PRD action buttons to prevent double-clicks
|
|
4135
|
-
function qaDisablePrdButtons() {
|
|
4136
|
-
const container = document.getElementById('qa-generate-prd-btn');
|
|
4137
|
-
if (container) container.querySelectorAll('button').forEach(b => { b.disabled = true; b.style.opacity = '0.5'; });
|
|
4138
|
-
}
|
|
4139
|
-
|
|
4140
|
-
// Show plan version action buttons (Run alongside / Replace / Just save)
|
|
4141
|
-
function showPlanVersionActions(thread, newFile, originalFile) {
|
|
4142
|
-
const esc = newFile.replace(/'/g, "\\'");
|
|
4143
|
-
// Look up existing PRD for the original plan's project
|
|
4144
|
-
const allPlans = window._lastStatus?.plans || [];
|
|
4145
|
-
const origPlan = allPlans.find(p => p.file === originalFile);
|
|
4146
|
-
const project = origPlan?.project || '';
|
|
4147
|
-
const existingPrd = allPlans.find(p => p.file.endsWith('.json') && p.project === project && p.status !== 'completed');
|
|
4148
|
-
|
|
4149
|
-
const btn = document.createElement('div');
|
|
4150
|
-
btn.id = 'qa-generate-prd-btn';
|
|
4151
|
-
btn.style.cssText = 'margin:8px 0;padding:8px 12px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:6px;display:flex;flex-wrap:wrap;align-items:center;gap:8px';
|
|
4152
|
-
|
|
4153
|
-
if (existingPrd) {
|
|
4154
|
-
btn.innerHTML = '<span style="color:var(--green);font-weight:600;font-size:12px;width:100%">New plan version created — existing PRD running</span>' +
|
|
4155
|
-
'<button onclick="qaNewPrd(\'' + esc + '\')" style="background:var(--green);color:#fff;border:none;border-radius:4px;padding:4px 12px;font-size:11px;font-weight:600;cursor:pointer" title="Execute this plan as a separate PRD alongside the current one">Run alongside</button>' +
|
|
4156
|
-
'<button onclick="qaReplacePrd(\'' + esc + '\')" style="background:var(--orange);color:#fff;border:none;border-radius:4px;padding:4px 12px;font-size:11px;font-weight:600;cursor:pointer" title="Pause existing PRD, clean pending items, execute this plan instead">Replace old PRD</button>' +
|
|
4157
|
-
'<button onclick="qaJustSave(this)" style="background:var(--surface2);color:var(--text);border:1px solid var(--border);border-radius:4px;padding:4px 12px;font-size:11px;cursor:pointer" title="Keep the new version saved without dispatching any work">Just save</button>' +
|
|
4158
|
-
'<span style="color:var(--muted);font-size:10px;width:100%">Run alongside keeps current work going. Replace pauses it and starts fresh.</span>';
|
|
4159
|
-
} else {
|
|
4160
|
-
btn.innerHTML = '<span style="color:var(--green);font-weight:600;font-size:12px;width:100%">New plan version created</span>' +
|
|
4161
|
-
'<button onclick="qaNewPrd(\'' + esc + '\')" style="background:var(--green);color:#fff;border:none;border-radius:4px;padding:4px 12px;font-size:11px;font-weight:600;cursor:pointer">Execute plan</button>' +
|
|
4162
|
-
'<button onclick="qaJustSave(this)" style="background:var(--surface2);color:var(--text);border:1px solid var(--border);border-radius:4px;padding:4px 12px;font-size:11px;cursor:pointer">Just save</button>' +
|
|
4163
|
-
'<span style="color:var(--muted);font-size:10px">Execute dispatches an agent to create PRD items from this plan</span>';
|
|
4164
|
-
}
|
|
4165
|
-
// Remove any previous action buttons
|
|
4166
|
-
const old = thread.querySelector('#qa-generate-prd-btn');
|
|
4167
|
-
if (old) old.remove();
|
|
4168
|
-
thread.appendChild(btn);
|
|
4169
|
-
}
|
|
4170
|
-
|
|
4171
|
-
function qaJustSave(el) {
|
|
4172
|
-
const container = el.closest('#qa-generate-prd-btn');
|
|
4173
|
-
if (container) container.innerHTML = '<span style="color:var(--muted);font-size:11px">Saved. No work dispatched.</span>';
|
|
4174
|
-
}
|
|
4175
|
-
|
|
4176
|
-
// Replace existing PRD: pause old, clean pending items, regenerate from revised plan
|
|
4177
|
-
async function qaReplacePrd(planFile) {
|
|
4178
|
-
qaDisablePrdButtons();
|
|
4179
|
-
const allPlans = window._lastStatus?.plans || [];
|
|
4180
|
-
const mdPlan = allPlans.find(p => p.file === planFile);
|
|
4181
|
-
const project = mdPlan?.project || '';
|
|
4182
|
-
const existingPrd = allPlans.find(p => p.file.endsWith('.json') && p.project === project);
|
|
4183
|
-
|
|
4184
|
-
if (existingPrd) {
|
|
4185
|
-
// Pause first to stop materialization, then clean pending items
|
|
4186
|
-
try {
|
|
4187
|
-
await fetch('/api/plans/pause', {
|
|
4188
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
4189
|
-
body: JSON.stringify({ file: existingPrd.file })
|
|
4190
|
-
});
|
|
4191
|
-
} catch {}
|
|
4192
|
-
try {
|
|
4193
|
-
await fetch('/api/plans/regenerate', {
|
|
4194
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
4195
|
-
body: JSON.stringify({ source: existingPrd.file })
|
|
4196
|
-
});
|
|
4197
|
-
} catch {}
|
|
4198
|
-
}
|
|
4199
|
-
|
|
4200
|
-
planExecute(planFile, project, null);
|
|
4201
|
-
|
|
4202
|
-
const btn = document.getElementById('qa-generate-prd-btn');
|
|
4203
|
-
if (btn) btn.innerHTML = '<span style="color:var(--orange);font-size:12px">Replacing PRD — old items paused, agent regenerating from revised plan.</span>';
|
|
4204
|
-
}
|
|
4205
|
-
|
|
4206
|
-
// New PRD: keep existing PRD running, create fresh PRD from revised plan
|
|
4207
|
-
async function qaNewPrd(planFile) {
|
|
4208
|
-
qaDisablePrdButtons();
|
|
4209
|
-
const allPlans = window._lastStatus?.plans || [];
|
|
4210
|
-
const mdPlan = allPlans.find(p => p.file === planFile);
|
|
4211
|
-
const project = mdPlan?.project || '';
|
|
4212
|
-
|
|
4213
|
-
planExecute(planFile, project, null);
|
|
4214
|
-
|
|
4215
|
-
const btn = document.getElementById('qa-generate-prd-btn');
|
|
4216
|
-
if (btn) btn.innerHTML = '<span style="color:var(--green);font-size:12px">New PRD dispatched — existing work continues, agent creating fresh PRD from revised plan.</span>';
|
|
4217
|
-
}
|
|
4218
|
-
|
|
4219
4126
|
async function planExecute(file, project, btn) {
|
|
4220
4127
|
if (btn) { btn.textContent = 'Executing...'; btn.disabled = true; btn.style.color = 'var(--blue)'; }
|
|
4221
4128
|
try {
|
|
@@ -4429,7 +4336,6 @@ async function planView(file) {
|
|
|
4429
4336
|
// Clear notification badge when opening this document
|
|
4430
4337
|
const card = findCardForFile(_modalFilePath);
|
|
4431
4338
|
if (card) clearNotifBadge(card);
|
|
4432
|
-
// steer btn removed — unified send
|
|
4433
4339
|
document.getElementById('modal').classList.add('open');
|
|
4434
4340
|
} catch (e) { console.error(e); }
|
|
4435
4341
|
}
|
|
@@ -4568,7 +4474,6 @@ async function kbOpenItem(category, file) {
|
|
|
4568
4474
|
// Clear notification badge when opening this document
|
|
4569
4475
|
const card = findCardForFile(_modalFilePath);
|
|
4570
4476
|
if (card) clearNotifBadge(card);
|
|
4571
|
-
// steer btn removed — unified send
|
|
4572
4477
|
document.getElementById('modal').classList.add('open');
|
|
4573
4478
|
} catch (e) {
|
|
4574
4479
|
console.error('Failed to load KB item:', e);
|
package/dashboard.js
CHANGED
|
@@ -1857,7 +1857,7 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
|
|
|
1857
1857
|
for (const w of items) {
|
|
1858
1858
|
if (w.sourcePlan !== body.file) continue;
|
|
1859
1859
|
// Keep completed items as-is, reset everything else to pending.
|
|
1860
|
-
if (w.status === 'done'
|
|
1860
|
+
if (w.status === 'done') continue;
|
|
1861
1861
|
|
|
1862
1862
|
if (w.status === 'dispatched') {
|
|
1863
1863
|
// Kill the agent working on this item, if any.
|
|
@@ -2259,148 +2259,6 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
|
|
|
2259
2259
|
} catch (e) { return jsonReply(res, 400, { error: e.message }); }
|
|
2260
2260
|
}
|
|
2261
2261
|
|
|
2262
|
-
// POST /api/plans/revise-and-regenerate — REMOVED: plan versioning now handled by /api/doc-chat
|
|
2263
|
-
// The "Replace old PRD" flow uses qaReplacePrd (frontend) which calls /api/plans/pause + /api/plans/regenerate + planExecute
|
|
2264
|
-
async function handlePlansReviseAndRegenerate(req, res) {
|
|
2265
|
-
try {
|
|
2266
|
-
const body = await readBody(req);
|
|
2267
|
-
if (!body.source || !body.instruction) return jsonReply(res, 400, { error: 'source and instruction required' });
|
|
2268
|
-
|
|
2269
|
-
// Find the source plan .md file for this PRD
|
|
2270
|
-
// Convention: PRD JSON references plan via plan_summary containing the work item ID,
|
|
2271
|
-
// or the .md file has a matching name prefix
|
|
2272
|
-
const prdPath = path.join(PRD_DIR, body.source);
|
|
2273
|
-
if (!fs.existsSync(prdPath)) return jsonReply(res, 404, { error: 'PRD file not found' });
|
|
2274
|
-
|
|
2275
|
-
// Look for corresponding .md plan file
|
|
2276
|
-
let sourcePlanFile = null;
|
|
2277
|
-
const planFiles = safeReadDir(PLANS_DIR).filter(f => f.endsWith('.md'));
|
|
2278
|
-
if (body.sourcePlan) {
|
|
2279
|
-
// Explicit source plan provided
|
|
2280
|
-
sourcePlanFile = body.sourcePlan;
|
|
2281
|
-
} else {
|
|
2282
|
-
// Heuristic: find .md plan by matching prefix or by reading PRD's generated_from field
|
|
2283
|
-
const prd = JSON.parse(safeRead(prdPath) || '{}');
|
|
2284
|
-
if (prd.source_plan) {
|
|
2285
|
-
sourcePlanFile = prd.source_plan;
|
|
2286
|
-
} else {
|
|
2287
|
-
// Match by prefix: officeagent-2026-03-15.json → plan-*officeagent* or plan-w025*.md
|
|
2288
|
-
const prdBase = body.source.replace('.json', '');
|
|
2289
|
-
for (const f of planFiles) {
|
|
2290
|
-
// Check if plan file mentions the same project or was created around same time
|
|
2291
|
-
const content = safeRead(path.join(PLANS_DIR, f)) || '';
|
|
2292
|
-
if (content.includes(prd.project || '___nomatch___') || content.includes(prd.plan_summary?.slice(0, 40) || '___nomatch___')) {
|
|
2293
|
-
sourcePlanFile = f;
|
|
2294
|
-
break;
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2297
|
-
// Last resort: most recent .md plan
|
|
2298
|
-
if (!sourcePlanFile && planFiles.length > 0) {
|
|
2299
|
-
sourcePlanFile = planFiles.sort((a, b) => {
|
|
2300
|
-
try { return fs.statSync(path.join(PLANS_DIR, b)).mtimeMs - fs.statSync(path.join(PLANS_DIR, a)).mtimeMs; } catch { return 0; }
|
|
2301
|
-
})[0];
|
|
2302
|
-
}
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
|
|
2306
|
-
if (!sourcePlanFile) {
|
|
2307
|
-
return jsonReply(res, 404, { error: 'No source plan (.md) found for this PRD. You can edit the PRD JSON directly using "Edit Plan".' });
|
|
2308
|
-
}
|
|
2309
|
-
|
|
2310
|
-
const sourcePlanPath = path.join(PLANS_DIR, sourcePlanFile);
|
|
2311
|
-
const planContent = safeRead(sourcePlanPath);
|
|
2312
|
-
if (!planContent) return jsonReply(res, 404, { error: 'Source plan file not readable: ' + sourcePlanFile });
|
|
2313
|
-
|
|
2314
|
-
// Step 1: Steer the source plan with the user's instruction via CC
|
|
2315
|
-
const result = await ccDocCall({
|
|
2316
|
-
message: body.instruction,
|
|
2317
|
-
document: planContent,
|
|
2318
|
-
title: sourcePlanFile,
|
|
2319
|
-
filePath: 'plans/' + sourcePlanFile,
|
|
2320
|
-
selection: body.selection || '',
|
|
2321
|
-
canEdit: true,
|
|
2322
|
-
isJson: false,
|
|
2323
|
-
});
|
|
2324
|
-
|
|
2325
|
-
if (!result.content) {
|
|
2326
|
-
return jsonReply(res, 200, { ok: true, answer: result.answer, updated: false });
|
|
2327
|
-
}
|
|
2328
|
-
|
|
2329
|
-
// Save the revised plan
|
|
2330
|
-
safeWrite(sourcePlanPath, result.content);
|
|
2331
|
-
|
|
2332
|
-
// Step 2: Pause the old PRD so it stops materializing items
|
|
2333
|
-
const prd = JSON.parse(safeRead(prdPath) || '{}');
|
|
2334
|
-
prd.status = 'revision-requested';
|
|
2335
|
-
prd.revision_feedback = body.instruction;
|
|
2336
|
-
prd.revisionRequestedAt = new Date().toISOString();
|
|
2337
|
-
safeWrite(prdPath, prd);
|
|
2338
|
-
|
|
2339
|
-
// Step 3: Clean up pending/failed work items from old PRD
|
|
2340
|
-
let reset = 0, kept = 0;
|
|
2341
|
-
const wiPaths = [{ path: path.join(MINIONS_DIR, 'work-items.json'), label: 'central' }];
|
|
2342
|
-
for (const proj of PROJECTS) {
|
|
2343
|
-
wiPaths.push({ path: shared.projectWorkItemsPath(proj), label: proj.name });
|
|
2344
|
-
}
|
|
2345
|
-
const deletedItemIds = [];
|
|
2346
|
-
for (const wiInfo of wiPaths) {
|
|
2347
|
-
try {
|
|
2348
|
-
const items = safeJson(wiInfo.path);
|
|
2349
|
-
const filtered = [];
|
|
2350
|
-
for (const w of items) {
|
|
2351
|
-
if (w.sourcePlan === body.source) {
|
|
2352
|
-
if (w.status === 'pending' || w.status === 'failed') {
|
|
2353
|
-
reset++;
|
|
2354
|
-
deletedItemIds.push(w.id);
|
|
2355
|
-
} else {
|
|
2356
|
-
kept++;
|
|
2357
|
-
filtered.push(w);
|
|
2358
|
-
}
|
|
2359
|
-
} else {
|
|
2360
|
-
filtered.push(w);
|
|
2361
|
-
}
|
|
2362
|
-
}
|
|
2363
|
-
if (filtered.length < items.length) safeWrite(wiInfo.path, filtered);
|
|
2364
|
-
} catch (e) { console.error('work item deletion:', e.message); }
|
|
2365
|
-
}
|
|
2366
|
-
for (const itemId of deletedItemIds) {
|
|
2367
|
-
cleanDispatchEntries(d =>
|
|
2368
|
-
d.meta?.item?.sourcePlan === body.source && d.meta?.item?.id === itemId
|
|
2369
|
-
);
|
|
2370
|
-
}
|
|
2371
|
-
|
|
2372
|
-
// Step 4: Dispatch plan-to-prd to regenerate PRD from revised plan
|
|
2373
|
-
const centralWiPath = path.join(MINIONS_DIR, 'work-items.json');
|
|
2374
|
-
let centralItems = [];
|
|
2375
|
-
try { centralItems = JSON.parse(safeRead(centralWiPath) || '[]'); } catch {}
|
|
2376
|
-
const wiId = 'W-' + shared.uid();
|
|
2377
|
-
centralItems.push({
|
|
2378
|
-
id: wiId,
|
|
2379
|
-
title: 'Regenerate PRD from revised plan: ' + sourcePlanFile,
|
|
2380
|
-
type: 'plan-to-prd',
|
|
2381
|
-
priority: 'high',
|
|
2382
|
-
description: `The source plan \`${sourcePlanFile}\` has been revised. Convert it into a fresh PRD JSON.\n\nRevision instruction: ${body.instruction}\n\nRead the revised plan, generate updated PRD items (missing_features), and write to \`prd/${body.source}\`. Set status to "approved". Include \`"source_plan": "${sourcePlanFile}"\` in the JSON root.\n\nPreserve items that are already done (status "implemented" or "complete"). Reset or replace items that were pending/failed.`,
|
|
2383
|
-
status: 'pending',
|
|
2384
|
-
created: new Date().toISOString(),
|
|
2385
|
-
createdBy: 'dashboard:revise-and-regenerate',
|
|
2386
|
-
project: prd.project || '',
|
|
2387
|
-
planFile: sourcePlanFile,
|
|
2388
|
-
});
|
|
2389
|
-
safeWrite(centralWiPath, centralItems);
|
|
2390
|
-
|
|
2391
|
-
return jsonReply(res, 200, {
|
|
2392
|
-
ok: true,
|
|
2393
|
-
answer: result.answer,
|
|
2394
|
-
updated: true,
|
|
2395
|
-
sourcePlan: sourcePlanFile,
|
|
2396
|
-
prdPaused: true,
|
|
2397
|
-
reset,
|
|
2398
|
-
kept,
|
|
2399
|
-
workItemId: wiId,
|
|
2400
|
-
});
|
|
2401
|
-
} catch (e) { return jsonReply(res, 500, { error: e.message }); }
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
2262
|
async function handlePlansDiscuss(req, res) {
|
|
2405
2263
|
try {
|
|
2406
2264
|
const body = await readBody(req);
|
|
@@ -2570,7 +2428,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
2570
2428
|
let changed = false;
|
|
2571
2429
|
for (const w of items) {
|
|
2572
2430
|
if (w.sourcePlan !== f) continue;
|
|
2573
|
-
if (w.status === 'done'
|
|
2431
|
+
if (w.status === 'done') continue;
|
|
2574
2432
|
if (w.status === 'dispatched') {
|
|
2575
2433
|
const activeEntry = (dispatch.active || []).find(d => d.meta?.item?.id === w.id || d.meta?.dispatchKey?.includes(w.id));
|
|
2576
2434
|
if (activeEntry) {
|
package/docs/deprecated.json
CHANGED
|
@@ -1,83 +1 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"id": "status-in-pr",
|
|
4
|
-
"summary": "in-pr status alias — backward compat shim for done",
|
|
5
|
-
"deprecated": "2026-03-21",
|
|
6
|
-
"reason": "Simplified status model: agents mark items done directly, no intermediate in-pr state",
|
|
7
|
-
"locations": [
|
|
8
|
-
"dashboard.html: CSS classes, progress bar, status labels, graph colors (~10 locations)",
|
|
9
|
-
"dashboard.js:1525 completedStatuses set",
|
|
10
|
-
"engine.js:1165 PRD_MET_STATUSES set",
|
|
11
|
-
"engine.js:1180 dependency check",
|
|
12
|
-
"engine.js:1974 completedStatuses set",
|
|
13
|
-
"engine/lifecycle.js:54,61 plan completion gate",
|
|
14
|
-
"engine/queries.js:466,580,597 status ordering and counting"
|
|
15
|
-
],
|
|
16
|
-
"cleanup": "Remove in-pr from all status checks, CSS, and display logic. Only keep done."
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"id": "status-implemented",
|
|
20
|
-
"summary": "implemented status alias — legacy alias for done",
|
|
21
|
-
"deprecated": "2026-03-21",
|
|
22
|
-
"reason": "Canonical status is done. implemented was the original name before standardization.",
|
|
23
|
-
"locations": [
|
|
24
|
-
"dashboard.html: CSS, progress filters, status labels (~8 locations)",
|
|
25
|
-
"dashboard.js:1525 completedStatuses set",
|
|
26
|
-
"engine.js:1165,1974 status sets",
|
|
27
|
-
"engine/lifecycle.js:694 sets implemented on post-merge"
|
|
28
|
-
],
|
|
29
|
-
"cleanup": "Replace all implemented references with done. Update lifecycle.js post-merge to set done."
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"id": "status-complete",
|
|
33
|
-
"summary": "complete status alias — another legacy alias for done",
|
|
34
|
-
"deprecated": "2026-03-21",
|
|
35
|
-
"reason": "Canonical status is done. complete appeared in early PRD schemas.",
|
|
36
|
-
"locations": [
|
|
37
|
-
"dashboard.html: progress filters, completion checks (~4 locations)",
|
|
38
|
-
"engine.js:1165 PRD_MET_STATUSES set"
|
|
39
|
-
],
|
|
40
|
-
"cleanup": "Remove complete from all status checks. Only keep done."
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"id": "dead-plan-version-actions",
|
|
44
|
-
"summary": "showPlanVersionActions, qaJustSave, qaReplacePrd, qaNewPrd, qaDisablePrdButtons — dead code",
|
|
45
|
-
"deprecated": "2026-03-21",
|
|
46
|
-
"reason": "Doc-chat fork logic removed. These functions are unreachable.",
|
|
47
|
-
"locations": [
|
|
48
|
-
"dashboard.html:3775-3860 five function definitions (~80 lines)"
|
|
49
|
-
],
|
|
50
|
-
"cleanup": "Delete the five functions entirely."
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
"id": "dead-modal-original-plan",
|
|
54
|
-
"summary": "_modalOriginalPlan variable — dead code",
|
|
55
|
-
"deprecated": "2026-03-21",
|
|
56
|
-
"reason": "Tracked original plan for fork edits. Fork logic removed.",
|
|
57
|
-
"locations": [
|
|
58
|
-
"dashboard.html:3187 declaration",
|
|
59
|
-
"dashboard.html:2018 reset in closeModal"
|
|
60
|
-
],
|
|
61
|
-
"cleanup": "Delete the variable declaration and all references."
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"id": "dead-revise-and-regenerate",
|
|
65
|
-
"summary": "/api/plans/revise-and-regenerate endpoint — disabled behind if(false)",
|
|
66
|
-
"deprecated": "2026-03-21",
|
|
67
|
-
"reason": "Plan versioning handled differently now. Endpoint was explicitly disabled.",
|
|
68
|
-
"locations": [
|
|
69
|
-
"dashboard.js:1782-1829 (~45 lines of dead code)"
|
|
70
|
-
],
|
|
71
|
-
"cleanup": "Delete the entire if(false) block."
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"id": "dead-steer-btn-comments",
|
|
75
|
-
"summary": "// steer btn removed — unified send comments",
|
|
76
|
-
"deprecated": "2026-03-21",
|
|
77
|
-
"reason": "Steer button was removed long ago. Comments are noise.",
|
|
78
|
-
"locations": [
|
|
79
|
-
"dashboard.html: 4 occurrences"
|
|
80
|
-
],
|
|
81
|
-
"cleanup": "Delete the comments."
|
|
82
|
-
}
|
|
83
|
-
]
|
|
1
|
+
[]
|