@yemi33/minions 0.1.829 → 0.1.831
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 +3 -1
- package/dashboard.js +15 -28
- package/engine/shared.js +29 -1
- package/engine.js +11 -25
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.831 (2026-04-11)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
- stale PRD shows Regenerate PRD + Resume as-is buttons
|
|
7
7
|
|
|
8
8
|
### Fixes
|
|
9
|
+
- only 'updated' re-opens done work items, remove 'planned' status
|
|
9
10
|
- revert doc-chat MAX_HEIGHT to 500px
|
|
10
11
|
- hide plan card action buttons when stale banner is showing
|
|
11
12
|
- hide conflicting action buttons when stale PRD banner is showing
|
|
12
13
|
- diff-aware plan-to-prd triggered by Resume, not auto-dispatch
|
|
13
14
|
|
|
14
15
|
### Other
|
|
16
|
+
- refactor: add PRD_ITEM_STATUS/PRD_MATERIALIZABLE constants, extract queuePlanToPrd
|
|
15
17
|
- refactor: remove dead criteria variable, DRY plan resume functions
|
|
16
18
|
|
|
17
19
|
## 0.1.823 (2026-04-11)
|
package/dashboard.js
CHANGED
|
@@ -2247,34 +2247,21 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
|
|
|
2247
2247
|
const projectName = plan.project || body.file.replace(/-\d{4}-\d{2}-\d{2}\.json$/, '');
|
|
2248
2248
|
const targetProject = PROJECTS.find(p => p.name?.toLowerCase() === projectName.toLowerCase()) || PROJECTS[0];
|
|
2249
2249
|
if (targetProject) {
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
`- New items in the plan → set status "missing" (engine will materialize)\n` +
|
|
2266
|
-
`- Items removed from the plan → drop from PRD (engine will cancel pending WIs)\n` +
|
|
2267
|
-
`- Preserve all existing item IDs for unchanged/modified items — do NOT generate new IDs for them`,
|
|
2268
|
-
status: 'pending',
|
|
2269
|
-
created: new Date().toISOString(),
|
|
2270
|
-
createdBy: 'dashboard:plan-resume',
|
|
2271
|
-
project: targetProject.name,
|
|
2272
|
-
planFile: plan.source_plan,
|
|
2273
|
-
_existingPrdFile: body.file,
|
|
2274
|
-
});
|
|
2275
|
-
diffAwareQueued = true;
|
|
2276
|
-
return items;
|
|
2277
|
-
}, { defaultValue: [] });
|
|
2250
|
+
diffAwareQueued = shared.queuePlanToPrd({
|
|
2251
|
+
planFile: plan.source_plan, prdFile: body.file,
|
|
2252
|
+
title: `Update PRD from revised plan: ${plan.source_plan}`,
|
|
2253
|
+
description: `Plan file: plans/${plan.source_plan}\nPRD file: prd/${body.file}\n\n` +
|
|
2254
|
+
`Source plan was revised. Compare the updated plan against existing PRD and produce an updated version.\n\n` +
|
|
2255
|
+
`**Current PRD implementation state:**\n${implContext}\n\n` +
|
|
2256
|
+
`**Rules for updating:**\n` +
|
|
2257
|
+
`- Items that are done and unchanged in the plan → keep status "done" (preserve their ID)\n` +
|
|
2258
|
+
`- Items that are done but modified in the plan (new requirements) → set status "updated" (engine will re-open)\n` +
|
|
2259
|
+
`- New items in the plan → set status "missing" (engine will materialize)\n` +
|
|
2260
|
+
`- Items removed from the plan → drop from PRD (engine will cancel pending WIs)\n` +
|
|
2261
|
+
`- Preserve all existing item IDs for unchanged/modified items — do NOT generate new IDs for them`,
|
|
2262
|
+
project: targetProject.name, createdBy: 'dashboard:plan-resume',
|
|
2263
|
+
extra: { _existingPrdFile: body.file },
|
|
2264
|
+
});
|
|
2278
2265
|
}
|
|
2279
2266
|
}
|
|
2280
2267
|
|
package/engine/shared.js
CHANGED
|
@@ -587,6 +587,8 @@ const PLAN_STATUS = {
|
|
|
587
587
|
PAUSED: 'paused', REJECTED: 'rejected', COMPLETED: 'completed',
|
|
588
588
|
REVISION_REQUESTED: 'revision-requested',
|
|
589
589
|
};
|
|
590
|
+
const PRD_ITEM_STATUS = { MISSING: 'missing', UPDATED: 'updated', DONE: 'done' };
|
|
591
|
+
const PRD_MATERIALIZABLE = new Set([PRD_ITEM_STATUS.MISSING, PRD_ITEM_STATUS.UPDATED]);
|
|
590
592
|
const PR_STATUS = { ACTIVE: 'active', MERGED: 'merged', ABANDONED: 'abandoned', CLOSED: 'closed', LINKED: 'linked' };
|
|
591
593
|
// PRs eligible for polling (status/build/comment checks) — excludes terminal statuses
|
|
592
594
|
const PR_POLLABLE_STATUSES = new Set([PR_STATUS.ACTIVE, PR_STATUS.LINKED]);
|
|
@@ -605,6 +607,32 @@ function trackReviewMetric(pr, newReviewStatus, config) {
|
|
|
605
607
|
});
|
|
606
608
|
} catch (err) { log('warn', `Metrics update: ${err.message}`); }
|
|
607
609
|
}
|
|
610
|
+
|
|
611
|
+
/** Queue a plan-to-prd work item with dedup check inside lock. Returns true if queued. */
|
|
612
|
+
function queuePlanToPrd({ planFile, prdFile, title, description, project, createdBy, extra }) {
|
|
613
|
+
const centralWiPath = path.join(__dirname, '..', 'work-items.json');
|
|
614
|
+
let queued = false;
|
|
615
|
+
mutateJsonFileLocked(centralWiPath, items => {
|
|
616
|
+
if (!Array.isArray(items)) items = [];
|
|
617
|
+
if (items.some(w => w.type === 'plan-to-prd' && w.planFile === planFile && (w.status === 'pending' || w.status === 'dispatched'))) return items;
|
|
618
|
+
items.push({
|
|
619
|
+
id: 'W-' + uid(),
|
|
620
|
+
title,
|
|
621
|
+
type: 'plan-to-prd',
|
|
622
|
+
priority: 'high',
|
|
623
|
+
description,
|
|
624
|
+
status: 'pending',
|
|
625
|
+
created: new Date().toISOString(),
|
|
626
|
+
createdBy,
|
|
627
|
+
project,
|
|
628
|
+
planFile,
|
|
629
|
+
...(extra || {}),
|
|
630
|
+
});
|
|
631
|
+
queued = true;
|
|
632
|
+
return items;
|
|
633
|
+
}, { defaultValue: [] });
|
|
634
|
+
return queued;
|
|
635
|
+
}
|
|
608
636
|
const DISPATCH_RESULT = { SUCCESS: 'success', ERROR: 'error', TIMEOUT: 'timeout' };
|
|
609
637
|
const PIPELINE_STATUS = {
|
|
610
638
|
PENDING: 'pending', RUNNING: 'running', COMPLETED: 'completed',
|
|
@@ -1021,7 +1049,7 @@ module.exports = {
|
|
|
1021
1049
|
KB_CATEGORIES,
|
|
1022
1050
|
classifyInboxItem,
|
|
1023
1051
|
ENGINE_DEFAULTS,
|
|
1024
|
-
WI_STATUS, DONE_STATUSES, PLAN_TERMINAL_STATUSES, WORK_TYPE, PLAN_STATUS, PR_STATUS, PR_POLLABLE_STATUSES, DISPATCH_RESULT, trackReviewMetric,
|
|
1052
|
+
WI_STATUS, DONE_STATUSES, PLAN_TERMINAL_STATUSES, WORK_TYPE, PLAN_STATUS, PRD_ITEM_STATUS, PRD_MATERIALIZABLE, PR_STATUS, PR_POLLABLE_STATUSES, DISPATCH_RESULT, trackReviewMetric, queuePlanToPrd,
|
|
1025
1053
|
PIPELINE_STATUS, STAGE_TYPE, MEETING_STATUS, AGENT_STATUS,
|
|
1026
1054
|
FAILURE_CLASS, ESCALATION_POLICY, COMPLETION_FIELDS,
|
|
1027
1055
|
DEFAULT_AGENT_METRICS,
|
package/engine.js
CHANGED
|
@@ -25,7 +25,7 @@ const fs = require('fs');
|
|
|
25
25
|
const path = require('path');
|
|
26
26
|
const shared = require('./engine/shared');
|
|
27
27
|
const { exec, execAsync, execSilent, runFile, ts, ENGINE_DEFAULTS: DEFAULTS,
|
|
28
|
-
WI_STATUS, DONE_STATUSES, WORK_TYPE, PLAN_STATUS, PR_STATUS, DISPATCH_RESULT, AGENT_STATUS } = shared;
|
|
28
|
+
WI_STATUS, DONE_STATUSES, WORK_TYPE, PLAN_STATUS, PRD_ITEM_STATUS, PRD_MATERIALIZABLE, PR_STATUS, DISPATCH_RESULT, AGENT_STATUS } = shared;
|
|
29
29
|
const queries = require('./engine/queries');
|
|
30
30
|
|
|
31
31
|
// ─── Paths ──────────────────────────────────────────────────────────────────
|
|
@@ -1358,26 +1358,12 @@ function materializePlansAsWorkItems(config) {
|
|
|
1358
1358
|
const allProjects = getProjects(config);
|
|
1359
1359
|
const targetProject = allProjects.find(p => p.name?.toLowerCase() === projectName.toLowerCase()) || allProjects[0];
|
|
1360
1360
|
if (targetProject) {
|
|
1361
|
-
const
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
id: 'W-' + shared.uid(),
|
|
1368
|
-
title: `Regenerate PRD from revised plan: ${plan.source_plan}`,
|
|
1369
|
-
type: 'plan-to-prd',
|
|
1370
|
-
priority: 'high',
|
|
1371
|
-
description: `Plan file: plans/${plan.source_plan}\nSource plan was revised (PRD was ${prdStatus}) — regenerating.${completedContext}`,
|
|
1372
|
-
status: 'pending',
|
|
1373
|
-
created: ts(),
|
|
1374
|
-
createdBy: 'engine:plan-revision',
|
|
1375
|
-
project: targetProject.name,
|
|
1376
|
-
planFile: plan.source_plan,
|
|
1377
|
-
});
|
|
1378
|
-
queued = true;
|
|
1379
|
-
return items;
|
|
1380
|
-
}, { defaultValue: [] });
|
|
1361
|
+
const queued = shared.queuePlanToPrd({
|
|
1362
|
+
planFile: plan.source_plan, prdFile: file,
|
|
1363
|
+
title: `Generate PRD from plan: ${plan.source_plan}`,
|
|
1364
|
+
description: `Plan file: plans/${plan.source_plan}\nSource plan was updated while PRD was awaiting approval — generating fresh PRD.${completedContext}`,
|
|
1365
|
+
project: targetProject.name, createdBy: 'engine:plan-revision',
|
|
1366
|
+
});
|
|
1381
1367
|
if (queued) log('info', `Queued plan-to-prd regeneration for revised plan ${plan.source_plan} (${completedItems.length} completed items to carry over)`);
|
|
1382
1368
|
}
|
|
1383
1369
|
}
|
|
@@ -1417,14 +1403,14 @@ function materializePlansAsWorkItems(config) {
|
|
|
1417
1403
|
// No project found — use central work-items.json (engine works without projects)
|
|
1418
1404
|
const useCentral = !defaultProject;
|
|
1419
1405
|
|
|
1420
|
-
const statusFilter =
|
|
1406
|
+
const statusFilter = PRD_MATERIALIZABLE;
|
|
1421
1407
|
// Also materialize in-pr/done items that never got a work item (race with PR status sync)
|
|
1422
1408
|
const allExistingWiIds = new Set();
|
|
1423
1409
|
for (const w of queries.getWorkItems()) {
|
|
1424
1410
|
if (w.id) allExistingWiIds.add(w.id);
|
|
1425
1411
|
}
|
|
1426
1412
|
const items = plan.missing_features.filter(f =>
|
|
1427
|
-
statusFilter.
|
|
1413
|
+
statusFilter.has(f.status) ||
|
|
1428
1414
|
(DONE_STATUSES.has(f.status) && f.id && !allExistingWiIds.has(f.id))
|
|
1429
1415
|
);
|
|
1430
1416
|
|
|
@@ -1472,9 +1458,9 @@ function materializePlansAsWorkItems(config) {
|
|
|
1472
1458
|
|
|
1473
1459
|
mutateWorkItems(wiPath, existingItems => {
|
|
1474
1460
|
for (const item of projItems) {
|
|
1475
|
-
// Re-open:
|
|
1461
|
+
// Re-open: only 'updated' re-opens a done work item (missing = new item, not re-open)
|
|
1476
1462
|
const existingWi = existingItems.find(w => w.id === item.id);
|
|
1477
|
-
const shouldReopen = item.status ===
|
|
1463
|
+
const shouldReopen = item.status === PRD_ITEM_STATUS.UPDATED;
|
|
1478
1464
|
if (existingWi && DONE_STATUSES.has(existingWi.status) && shouldReopen) {
|
|
1479
1465
|
existingWi.status = WI_STATUS.PENDING;
|
|
1480
1466
|
existingWi._reopened = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.831",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|