@yemi33/minions 0.1.822 → 0.1.824

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 CHANGED
@@ -1,6 +1,11 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.822 (2026-04-11)
3
+ ## 0.1.824 (2026-04-11)
4
+
5
+ ### Fixes
6
+ - diff-aware plan-to-prd triggered by Resume, not auto-dispatch
7
+
8
+ ## 0.1.823 (2026-04-11)
4
9
 
5
10
  ### Features
6
11
  - add resume-plan CC action for diff-aware plan updates
@@ -18,6 +23,7 @@
18
23
  - cap review→fix cycles at evalMaxIterations (default 3)
19
24
 
20
25
  ### Fixes
26
+ - clear planStale on approve/resume so materialization proceeds
21
27
  - doc-chat resize cap raised, modal overflow + flex body layout
22
28
  - prevent duplicate verify WIs per PRD, re-open on modified plan
23
29
  - strip ===ACTIONS=== server-side in streaming chunks (not client)
@@ -37,7 +43,6 @@
37
43
  - allow PRD item retry when work item is missing (closes #781) (#807)
38
44
  - handle force-pushed dep branches on retry (closes #738) (#806)
39
45
  - project-scoped skill work items instruct wrong file path format (closes #790) (#804)
40
- - move ignoredAuthors construction outside inner comment loop (ADO)
41
46
 
42
47
  ### Other
43
48
  - docs: diff-aware PRD update playbook + prioritize team memory in shared rules
package/dashboard.js CHANGED
@@ -961,6 +961,7 @@ const server = http.createServer(async (req, res) => {
961
961
  if (!plan) return jsonReply(res, 500, { error: 'Could not parse PRD file' });
962
962
  plan.status = 'approved';
963
963
  delete plan.completedAt;
964
+ delete plan.planStale;
964
965
  safeWrite(activePath, plan);
965
966
  }
966
967
 
@@ -2186,7 +2187,8 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
2186
2187
  plan.approvedAt = new Date().toISOString();
2187
2188
  plan.approvedBy = body.approvedBy || os.userInfo().username;
2188
2189
  delete plan.pausedAt;
2189
- delete plan._completionNotified; // Allow re-completion after new work finishes
2190
+ delete plan.planStale;
2191
+ delete plan._completionNotified;
2190
2192
  safeWrite(planPath, plan);
2191
2193
 
2192
2194
  // Resume paused work items across all projects
@@ -2225,11 +2227,63 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
2225
2227
  }, { defaultValue: { pending: [], active: [], completed: [] } });
2226
2228
  }
2227
2229
 
2230
+ // Diff-aware PRD update: if plan has done work and a source_plan .md, dispatch plan-to-prd
2231
+ // to compare the revised plan against existing implementation
2232
+ let diffAwareQueued = false;
2233
+ if (plan.source_plan && plan.missing_features) {
2234
+ const config = queries.getConfig();
2235
+ const allWorkItems = queries.getWorkItems(config);
2236
+ const planWis = allWorkItems.filter(w => w.sourcePlan === body.file && w.itemType !== 'pr' && w.itemType !== 'verify');
2237
+ const doneWis = planWis.filter(w => shared.DONE_STATUSES.has(w.status));
2238
+ if (doneWis.length > 0) {
2239
+ const allPrs = PROJECTS.flatMap(p => shared.safeJson(shared.projectPrPath(p)) || []);
2240
+ const prLinks = shared.getPrLinks();
2241
+ const implContext = (plan.missing_features || []).map(f => {
2242
+ const wi = planWis.find(w => w.id === f.id);
2243
+ const pr = allPrs.find(p => prLinks[p.id] === f.id || (p.prdItems || []).includes(f.id));
2244
+ return `- **${f.id}**: ${f.name} [status: ${wi?.status || f.status}]${pr ? ` (PR: ${pr.id}, branch: \`${pr.branch}\`)` : ''}`;
2245
+ }).join('\n');
2246
+
2247
+ const projectName = plan.project || body.file.replace(/-\d{4}-\d{2}-\d{2}\.json$/, '');
2248
+ const targetProject = PROJECTS.find(p => p.name?.toLowerCase() === projectName.toLowerCase()) || PROJECTS[0];
2249
+ if (targetProject) {
2250
+ const centralWiPath = path.join(MINIONS_DIR, 'work-items.json');
2251
+ mutateJsonFileLocked(centralWiPath, items => {
2252
+ if (!Array.isArray(items)) items = [];
2253
+ if (items.some(w => w.type === 'plan-to-prd' && w.planFile === plan.source_plan && (w.status === 'pending' || w.status === 'dispatched'))) return items;
2254
+ items.push({
2255
+ id: 'W-' + shared.uid(),
2256
+ title: `Update PRD from revised plan: ${plan.source_plan}`,
2257
+ type: 'plan-to-prd',
2258
+ priority: 'high',
2259
+ description: `Plan file: plans/${plan.source_plan}\nPRD file: prd/${body.file}\n\n` +
2260
+ `Source plan was revised. Compare the updated plan against existing implementation and update the PRD.\n\n` +
2261
+ `**Existing implementation state:**\n${implContext}\n\n` +
2262
+ `**Rules for updating:**\n` +
2263
+ `- Items that are done and unchanged in the plan → keep status "done" (preserve their ID)\n` +
2264
+ `- Items that are done but modified in the plan (new requirements) → set status "updated" (engine will re-open)\n` +
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: [] });
2278
+ }
2279
+ }
2280
+ }
2281
+
2228
2282
  // Teams notification for plan approval — non-blocking
2229
2283
  try { teams.teamsNotifyPlanEvent({ name: plan.plan_summary || body.file, file: body.file }, 'plan-approved').catch(() => {}); } catch {}
2230
2284
 
2231
2285
  invalidateStatusCache();
2232
- return jsonReply(res, 200, { ok: true, status: 'approved', resumedWorkItems: resumed });
2286
+ return jsonReply(res, 200, { ok: true, status: 'approved', resumedWorkItems: resumed, diffAwareUpdate: diffAwareQueued });
2233
2287
  } catch (e) { return jsonReply(res, 400, { error: e.message }); }
2234
2288
  }
2235
2289
 
package/engine.js CHANGED
@@ -1331,65 +1331,10 @@ function materializePlansAsWorkItems(config) {
1331
1331
  // Handle PRD based on current status
1332
1332
  const prdStatus = plan.status || (plan.requires_approval ? 'awaiting-approval' : null);
1333
1333
 
1334
- // Approved/completed PRDs with existing work: auto-dispatch diff-aware plan-to-prd update
1335
- if (prdStatus === PLAN_STATUS.APPROVED || prdStatus === PLAN_STATUS.COMPLETED) {
1336
- const allWorkItems = queries.getWorkItems(config);
1337
- const planWis = allWorkItems.filter(w => w.sourcePlan === file && w.itemType !== 'pr' && w.itemType !== 'verify');
1338
- const doneWis = planWis.filter(w => DONE_STATUSES.has(w.status));
1339
- if (doneWis.length > 0) {
1340
- const allPrs = getProjects(config).flatMap(p => safeJson(projectPrPath(p)) || []);
1341
- const prLinks = shared.getPrLinks();
1342
- const implContext = (plan.missing_features || []).map(f => {
1343
- const wi = planWis.find(w => w.id === f.id);
1344
- const pr = allPrs.find(p => prLinks[p.id] === f.id || (p.prdItems || []).includes(f.id));
1345
- return `- **${f.id}**: ${f.name} [status: ${wi?.status || f.status}]${pr ? ` (PR: ${pr.id}, branch: \`${pr.branch}\`)` : ''}`;
1346
- }).join('\n');
1347
-
1348
- const planContent = safeRead(path.join(PLANS_DIR, plan.source_plan));
1349
- if (planContent) {
1350
- const projectName = plan.project || file.replace(/-\d{4}-\d{2}-\d{2}\.json$/, '');
1351
- const allProjects = getProjects(config);
1352
- const targetProject = allProjects.find(p => p.name?.toLowerCase() === projectName.toLowerCase()) || allProjects[0];
1353
- if (targetProject) {
1354
- const centralWiPath = path.join(MINIONS_DIR, 'work-items.json');
1355
- let queued = false;
1356
- mutateJsonFileLocked(centralWiPath, items => {
1357
- if (!Array.isArray(items)) items = [];
1358
- if (items.some(w => w.type === WORK_TYPE.PLAN_TO_PRD && w.planFile === plan.source_plan && (w.status === WI_STATUS.PENDING || w.status === WI_STATUS.DISPATCHED))) return items;
1359
- items.push({
1360
- id: 'W-' + shared.uid(),
1361
- title: `Update PRD from revised plan: ${plan.source_plan}`,
1362
- type: 'plan-to-prd',
1363
- priority: 'high',
1364
- description: `Plan file: plans/${plan.source_plan}\nPRD file: prd/${file}\n\n` +
1365
- `Source plan was revised. Compare the updated plan against existing implementation and update the PRD.\n\n` +
1366
- `**Existing implementation state:**\n${implContext}\n\n` +
1367
- `**Rules for updating:**\n` +
1368
- `- Items that are done and unchanged in the plan → keep status "done" (preserve their ID)\n` +
1369
- `- Items that are done but modified in the plan (new requirements) → set status "updated" (engine will re-open)\n` +
1370
- `- New items in the plan → set status "missing" (engine will materialize)\n` +
1371
- `- Items removed from the plan → drop from PRD (engine will cancel pending WIs)\n` +
1372
- `- Preserve all existing item IDs for unchanged/modified items — do NOT generate new IDs for them`,
1373
- status: 'pending',
1374
- created: ts(),
1375
- createdBy: 'engine:plan-revision',
1376
- project: targetProject.name,
1377
- planFile: plan.source_plan,
1378
- _existingPrdFile: file,
1379
- });
1380
- queued = true;
1381
- return items;
1382
- }, { defaultValue: [] });
1383
- if (queued) log('info', `Queued diff-aware plan-to-prd update for ${plan.source_plan} (${doneWis.length} done, ${planWis.length} total items)`);
1384
- }
1385
- }
1386
- } else {
1387
- plan.planStale = true;
1388
- log('info', `PRD ${file} flagged as stale (plan revised while ${prdStatus}, no done items) — user can re-execute from dashboard`);
1389
- }
1390
- } else if (prdStatus === PLAN_STATUS.PAUSED) {
1334
+ // Approved/completed/paused PRDs: flag stale user clicks Resume to trigger diff-aware update
1335
+ if (prdStatus && prdStatus !== 'awaiting-approval') {
1391
1336
  plan.planStale = true;
1392
- log('info', `PRD ${file} flagged as stale (plan revised while paused) — user can re-execute from dashboard`);
1337
+ log('info', `PRD ${file} flagged as stale (plan revised while ${prdStatus}) — user can resume from dashboard`);
1393
1338
  }
1394
1339
 
1395
1340
  // Awaiting-approval PRDs: auto-regenerate (no work started yet, safe to replace)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.822",
3
+ "version": "0.1.824",
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"