@yemi33/minions 0.1.156 → 0.1.157

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,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.157 (2026-04-02)
4
+
5
+ ### Engine
6
+ - engine.js
7
+ - engine/ado.js
8
+ - engine/github.js
9
+ - engine/shared.js
10
+
11
+ ### Other
12
+ - pipelines/daily-standup.json
13
+ - test/unit.test.js
14
+
3
15
  ## 0.1.156 (2026-04-02)
4
16
 
5
17
  ### Engine
package/engine/ado.js CHANGED
@@ -386,19 +386,7 @@ async function reconcilePrs(config) {
386
386
  log('info', `PR reconciliation: added ${prId} (branch: ${branch}${confirmedItemId ? ', linked to ' + confirmedItemId : ''}) to ${project.name}`);
387
387
  }
388
388
 
389
- // Backfill prdItems from pr-links for any PR with empty array
390
- const prLinks = shared.getPrLinks();
391
- let backfilled = 0;
392
- for (const pr of existingPrs) {
393
- const linked = prLinks[pr.id];
394
- if (linked && !(pr.prdItems || []).includes(linked)) {
395
- pr.prdItems = Array.isArray(pr.prdItems) ? pr.prdItems : [];
396
- pr.prdItems.push(linked);
397
- backfilled++;
398
- }
399
- }
400
-
401
- if (projectAdded > 0 || projectUpdated > 0 || backfilled > 0) {
389
+ if (projectAdded > 0 || projectUpdated > 0) {
402
390
  shared.safeWrite(prPath, existingPrs);
403
391
  totalAdded += projectAdded;
404
392
  if (projectUpdated > 0) log('info', `PR reconciliation: linked ${projectUpdated} existing PR(s) to PRD items in ${project.name}`);
package/engine/github.js CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  const shared = require('./shared');
8
- const { exec, getProjects, projectPrPath, projectWorkItemsPath, safeJson, safeWrite, MINIONS_DIR, addPrLink, getPrLinks, log, dateStamp } = shared;
8
+ const { exec, getProjects, projectPrPath, projectWorkItemsPath, safeJson, safeWrite, MINIONS_DIR, addPrLink, log, dateStamp } = shared;
9
9
  const { getPrs } = require('./queries');
10
10
  const path = require('path');
11
11
 
@@ -371,19 +371,7 @@ async function reconcilePrs(config) {
371
371
  log('info', `GitHub PR reconciliation: added ${prId} (branch: ${branch}${confirmedItemId ? ', linked to ' + confirmedItemId : ''}) to ${project.name}`);
372
372
  }
373
373
 
374
- // Backfill prdItems from pr-links for any PR with empty array
375
- const prLinks = getPrLinks();
376
- let backfilled = 0;
377
- for (const pr of existingPrs) {
378
- const linked = prLinks[pr.id];
379
- if (linked && !(pr.prdItems || []).includes(linked)) {
380
- pr.prdItems = Array.isArray(pr.prdItems) ? pr.prdItems : [];
381
- pr.prdItems.push(linked);
382
- backfilled++;
383
- }
384
- }
385
-
386
- if (projectAdded > 0 || backfilled > 0) {
374
+ if (projectAdded > 0) {
387
375
  safeWrite(prPath, existingPrs);
388
376
  totalAdded += projectAdded;
389
377
  }
package/engine/shared.js CHANGED
@@ -404,10 +404,26 @@ function projectStateDir(project) {
404
404
  return dir;
405
405
  }
406
406
 
407
+ const CENTRAL_WI_PATH = path.join(MINIONS_DIR, 'work-items.json');
408
+
407
409
  function projectWorkItemsPath(project) {
408
410
  return path.join(projectStateDir(project), 'work-items.json');
409
411
  }
410
412
 
413
+ /**
414
+ * Resolve work-items.json path from dispatch meta.
415
+ * Central items → CENTRAL_WI_PATH; project items → projects/<name>/work-items.json.
416
+ */
417
+ function resolveWiPath(meta) {
418
+ if (meta.source === 'central-work-item' || meta.source === 'central-work-item-fanout') {
419
+ return CENTRAL_WI_PATH;
420
+ }
421
+ if (meta.project?.name) {
422
+ return path.join(MINIONS_DIR, 'projects', meta.project.name, 'work-items.json');
423
+ }
424
+ return null;
425
+ }
426
+
411
427
  function projectPrPath(project) {
412
428
  return path.join(projectStateDir(project), 'pull-requests.json');
413
429
  }
@@ -501,7 +517,7 @@ function parseSkillFrontmatter(content, filename) {
501
517
  // Never touched by polling loops — only written when a PR is first linked to a PRD item.
502
518
 
503
519
  function getPrLinks() {
504
- // Derive from PR.prdItems (single source of truth) + legacy pr-links.json as fallback
520
+ // Derive from PR.prdItems (single source of truth)
505
521
  const links = {};
506
522
  try {
507
523
  const projects = getProjects();
@@ -514,22 +530,15 @@ function getPrLinks() {
514
530
  }
515
531
  }
516
532
  } catch { /* optional */ }
517
- // Merge legacy pr-links.json for items not yet in PR.prdItems
518
- try {
519
- const legacy = JSON.parse(require('fs').readFileSync(PR_LINKS_PATH, 'utf8'));
520
- for (const [prId, itemId] of Object.entries(legacy)) {
521
- if (!links[prId]) links[prId] = itemId;
522
- }
523
- } catch { /* optional */ }
524
533
  return links;
525
534
  }
526
535
 
527
536
  function addPrLink(prId, itemId) {
528
537
  if (!prId || !itemId) return;
529
- const links = getPrLinks();
530
- if (links[prId] === itemId) return; // already correct, no write needed
531
- links[prId] = itemId;
532
- safeWrite(PR_LINKS_PATH, links);
538
+ try {
539
+ const projects = getProjects();
540
+ for (const project of projects) { linkPrToItem(project, prId, itemId); }
541
+ } catch { /* optional */ }
533
542
  }
534
543
 
535
544
  /**
@@ -592,7 +601,9 @@ module.exports = {
592
601
  getProjects,
593
602
  projectRoot,
594
603
  projectStateDir,
604
+ CENTRAL_WI_PATH,
595
605
  projectWorkItemsPath,
606
+ resolveWiPath,
596
607
  projectPrPath,
597
608
  getPrLinks,
598
609
  addPrLink,
package/engine.js CHANGED
@@ -24,7 +24,7 @@
24
24
  const fs = require('fs');
25
25
  const path = require('path');
26
26
  const shared = require('./engine/shared');
27
- const { exec, execSilent, runFile, ENGINE_DEFAULTS: DEFAULTS } = shared;
27
+ const { exec, execSilent, runFile, ENGINE_DEFAULTS: DEFAULTS, CENTRAL_WI_PATH, resolveWiPath } = shared;
28
28
  const queries = require('./engine/queries');
29
29
 
30
30
  // ─── Paths ──────────────────────────────────────────────────────────────────
@@ -879,7 +879,7 @@ const { COOLDOWN_PATH, dispatchCooldowns, loadCooldowns, saveCooldowns,
879
879
  // Auto-clean pending/failed work items for a PRD so they re-materialize with updated plan data
880
880
  function autoCleanPrdWorkItems(prdFile, config) {
881
881
  const allProjects = getProjects(config);
882
- const wiPaths = [path.join(MINIONS_DIR, 'work-items.json')];
882
+ const wiPaths = [CENTRAL_WI_PATH];
883
883
  for (const proj of allProjects) wiPaths.push(projectWorkItemsPath(proj));
884
884
  const deletedIds = [];
885
885
  for (const wiPath of wiPaths) {
@@ -1001,8 +1001,7 @@ function materializePlansAsWorkItems(config) {
1001
1001
  const allProjects = getProjects(config);
1002
1002
  const targetProject = allProjects.find(p => p.name?.toLowerCase() === projectName.toLowerCase()) || allProjects[0];
1003
1003
  if (targetProject) {
1004
- const centralWiPath = path.join(MINIONS_DIR, 'work-items.json');
1005
- const centralItems = safeJson(centralWiPath) || [];
1004
+ const centralItems = safeJson(CENTRAL_WI_PATH) || [];
1006
1005
  const alreadyQueued = centralItems.some(w =>
1007
1006
  w.type === 'plan-to-prd' && w.planFile === plan.source_plan && (w.status === 'pending' || w.status === 'dispatched')
1008
1007
  );
@@ -1070,7 +1069,7 @@ function materializePlansAsWorkItems(config) {
1070
1069
  }
1071
1070
  }
1072
1071
  // Also check central work-items.json
1073
- for (const w of (safeJson(path.join(MINIONS_DIR, 'work-items.json')) || [])) {
1072
+ for (const w of (safeJson(CENTRAL_WI_PATH) || [])) {
1074
1073
  if (w.id) allExistingWiIds.add(w.id);
1075
1074
  }
1076
1075
  const items = plan.missing_features.filter(f =>
@@ -1115,7 +1114,7 @@ function materializePlansAsWorkItems(config) {
1115
1114
 
1116
1115
  let totalCreated = 0;
1117
1116
  for (const [projName, { project, items: projItems }] of itemsByProject) {
1118
- const wiPath = project ? projectWorkItemsPath(project) : path.join(MINIONS_DIR, 'work-items.json');
1117
+ const wiPath = project ? projectWorkItemsPath(project) : CENTRAL_WI_PATH;
1119
1118
  const existingItems = safeJson(wiPath) || [];
1120
1119
  let created = 0;
1121
1120
  const newlyCreatedIds = new Set(); // tracks IDs created in this pass for reconciliation scoping
@@ -1768,7 +1767,7 @@ function extractSpecInfo(filePath, projectRoot_) {
1768
1767
  * Uses the shared work-item.md playbook with multi-project context injected.
1769
1768
  */
1770
1769
  function discoverCentralWorkItems(config) {
1771
- const centralPath = path.join(MINIONS_DIR, 'work-items.json');
1770
+ const centralPath = CENTRAL_WI_PATH;
1772
1771
  const items = safeJson(centralPath) || [];
1773
1772
  const projects = getProjects(config);
1774
1773
  const newWork = [];
@@ -2080,7 +2079,7 @@ function discoverWork(config) {
2080
2079
  const { discoverScheduledWork } = require('./engine/scheduler');
2081
2080
  const scheduledWork = discoverScheduledWork(config);
2082
2081
  if (scheduledWork.length > 0) {
2083
- const centralPath = path.join(MINIONS_DIR, 'work-items.json');
2082
+ const centralPath = CENTRAL_WI_PATH;
2084
2083
  const items = safeJson(centralPath) || [];
2085
2084
  let added = 0;
2086
2085
  for (const item of scheduledWork) {
@@ -2411,9 +2410,7 @@ async function tickInner() {
2411
2410
  // Defensive: ensure the work item is re-queued if completeDispatch didn't fire
2412
2411
  if (item.meta?.item?.id) {
2413
2412
  try {
2414
- const wiPath = item.meta.source === 'central-work-item' || item.meta.source === 'central-work-item-fanout'
2415
- ? path.join(ENGINE_DIR, '..', 'work-items.json')
2416
- : item.meta.project?.name ? projectWorkItemsPath({ name: item.meta.project.name, localPath: item.meta.project.localPath }) : null;
2413
+ const wiPath = resolveWiPath(item.meta);
2417
2414
  if (wiPath) {
2418
2415
  const items = safeJson(wiPath) || [];
2419
2416
  const wi = items.find(i => i.id === item.meta.item.id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.156",
3
+ "version": "0.1.157",
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"
@@ -0,0 +1,19 @@
1
+ {
2
+ "id": "daily-standup",
3
+ "title": "Daily Squad Stand-up",
4
+ "stages": [
5
+ {
6
+ "id": "standup",
7
+ "type": "meeting",
8
+ "title": "Daily Squad Stand-up � 2026-04-01",
9
+ "agenda": "Daily weekday meeting for all agents to review squad setup improvements and discuss progress on agentic harness engineering.\n\n1. What shipped since yesterday's meeting (Track A/B/C progress)?\n2. Any blockers on current work items?\n3. Review recent agentic harness engineering best practices � are there new Anthropic articles or model improvements that change our assumptions?\n4. Propose 1 concrete improvement each agent wants to make to the squad harness this week.\n5. Agree on today's priorities and any re-sequencing needed.\n\nOutput: a bulleted list of decisions made, action items with owners, and any updated priorities.",
10
+ "participants": [
11
+ "all"
12
+ ]
13
+ }
14
+ ],
15
+ "trigger": {
16
+ "cron": "0 9 1,2,3,4,5"
17
+ },
18
+ "enabled": true
19
+ }