@yemi33/minions 0.1.646 → 0.1.647

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,8 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.646 (2026-04-09)
3
+ ## 0.1.647 (2026-04-09)
4
4
 
5
5
  ### Features
6
+ - structured note IDs for inbox notes
6
7
  - pipeline plan stage reconciliation and UX fixes
7
8
  - track notes, plans, and PRDs as work item artifacts
8
9
 
@@ -454,7 +454,10 @@ function openWorkItemDetail(id) {
454
454
  if (arts.plan) artPills += '<span onclick="planView(\'' + escHtml(arts.plan) + '\')" style="' + pillStyle + '">📋 Plan</span> ';
455
455
  if (arts.prd) artPills += '<span onclick="planView(\'' + escHtml(arts.prd) + '\')" style="' + pillStyle + '">📄 PRD</span> ';
456
456
  if (arts.sourcePlan) artPills += '<span onclick="planView(\'' + escHtml(arts.sourcePlan) + '\')" style="' + pillStyle + '">📋 Source Plan</span> ';
457
- if (arts.notes && arts.notes.length > 0) arts.notes.forEach(function(n) { artPills += '<span onclick="closeModal();switchPage(\'inbox\')" style="' + pillStyle + '">📝 ' + escHtml(n.replace(/\.md$/, '').slice(0, 30)) + '</span> '; });
457
+ if (arts.notes && arts.notes.length > 0) arts.notes.forEach(function(n) {
458
+ var noteLabel = typeof n === 'object' ? (n.id || n.file || 'note').slice(0, 30) : String(n).replace(/\.md$/, '').slice(0, 30);
459
+ artPills += '<span onclick="closeModal();switchPage(\'inbox\')" style="' + pillStyle + '">📝 ' + escHtml(noteLabel) + '</span> ';
460
+ });
458
461
  if (arts.skills && arts.skills.length > 0) arts.skills.forEach(function(s) { artPills += '<span onclick="openSkill(\'' + escHtml(s) + '\',\'minions\',\'\')" style="' + pillStyle + '">⚙ ' + escHtml(s) + '</span> '; });
459
462
  if (artPills) html += field('Artifacts', '<div style="display:flex;flex-wrap:wrap;gap:4px">' + artPills + '</div>');
460
463
 
@@ -250,8 +250,11 @@ function renderPlaybook(type, vars) {
250
250
  const timeStamp = ts().slice(11, 16).replace(':', '');
251
251
  const inboxSlug = [vars.agent_id || 'agent', vars.task_id || '', dateStamp(), timeStamp].filter(Boolean).join('-');
252
252
  content += `\n\n---\n\n## REQUIRED: Write Learnings\n\n`;
253
+ const noteId = `NOTE-${shared.uid()}`;
253
254
  content += `After completing your task, write **one** findings file to:\n`;
254
255
  content += `\`${MINIONS_DIR}/notes/inbox/${inboxSlug}.md\`\n\n`;
256
+ content += `Start the file with this YAML frontmatter (required for tracking):\n`;
257
+ content += `\`\`\`\n---\nid: ${noteId}\nagent: ${vars.agent_id || 'agent'}\ndate: ${dateStamp()}\n---\n\`\`\`\n\n`;
255
258
  content += `**IMPORTANT: Write exactly ONE inbox file per task.** If the playbook above already specifies an inbox path, use THAT path instead and include your learnings in the same document. Do NOT create a second file — duplicates clog consolidation.\n\n`;
256
259
  content += `Include in your findings file:\n`;
257
260
  content += `- What you learned about the codebase\n`;
package/engine/shared.js CHANGED
@@ -286,15 +286,30 @@ function uniquePath(filePath) {
286
286
  * @param {string} content - Markdown content to write
287
287
  * @returns {boolean} true if a write occurred, false if deduped/skipped
288
288
  */
289
+ /**
290
+ * Extract note ID from frontmatter of an inbox file. Returns null if no ID found.
291
+ */
292
+ function parseNoteId(content) {
293
+ if (!content) return null;
294
+ const m = content.match(/^---\n[\s\S]*?id:\s*(NOTE-\w+)[\s\S]*?---/);
295
+ return m ? m[1] : null;
296
+ }
297
+
289
298
  function writeToInbox(agentId, slug, content, _inboxDir) {
290
299
  try {
291
300
  const inboxDir = _inboxDir || path.join(MINIONS_DIR, 'notes', 'inbox');
292
301
  const prefix = `${agentId}-${slug}-${dateStamp()}`;
293
302
  const existing = safeReadDir(inboxDir).find(f => f.startsWith(prefix));
294
303
  if (existing) return false;
304
+ const noteId = `NOTE-${uid()}`;
305
+ // Inject structured ID as YAML frontmatter if content doesn't already have it
306
+ const hasFrontmatter = content.trimStart().startsWith('---');
307
+ const tagged = hasFrontmatter
308
+ ? content.replace(/^---\n/, `---\nid: ${noteId}\n`)
309
+ : `---\nid: ${noteId}\nagent: ${agentId}\ndate: ${dateStamp()}\n---\n\n${content}`;
295
310
  const filePath = path.join(inboxDir, `${prefix}.md`);
296
- safeWrite(filePath, content);
297
- return true;
311
+ safeWrite(filePath, tagged);
312
+ return noteId;
298
313
  } catch (e) {
299
314
  log('warn', `writeToInbox failed: ${e.message}`);
300
315
  return false;
@@ -860,7 +875,7 @@ module.exports = {
860
875
  mutatePullRequests,
861
876
  uid,
862
877
  uniquePath,
863
- writeToInbox,
878
+ writeToInbox, parseNoteId,
864
879
  exec,
865
880
  execAsync,
866
881
  execSilent,
package/engine.js CHANGED
@@ -791,11 +791,18 @@ async function spawnAgent(dispatchItem, config) {
791
791
  try {
792
792
  const artWiPath = resolveWorkItemPath(dispatchItem.meta);
793
793
  if (artWiPath) {
794
- // Collect inbox notes written by this agent today
794
+ // Collect inbox notes written by this agent today (with structured IDs if available)
795
795
  const _artToday = shared.dateStamp();
796
796
  const _artInboxDir = path.join(MINIONS_DIR, 'notes', 'inbox');
797
797
  let _artNotes = [];
798
- try { _artNotes = shared.safeReadDir(_artInboxDir).filter(f => f.startsWith(agentId + '-') && f.includes(_artToday)); } catch {}
798
+ try {
799
+ const noteFiles = shared.safeReadDir(_artInboxDir).filter(f => f.startsWith(agentId + '-') && f.includes(_artToday));
800
+ for (const f of noteFiles) {
801
+ const content = shared.safeRead(path.join(_artInboxDir, f));
802
+ const noteId = shared.parseNoteId(content);
803
+ _artNotes.push({ file: f, id: noteId || f.replace(/\.md$/, '') });
804
+ }
805
+ } catch {}
799
806
 
800
807
  mutateJsonFileLocked(artWiPath, data => {
801
808
  if (!Array.isArray(data)) return data;
@@ -806,7 +813,7 @@ async function spawnAgent(dispatchItem, config) {
806
813
  if (dispatchItem.meta.branch) arts.branch = dispatchItem.meta.branch;
807
814
  if (wi._pr) arts.pr = wi._pr;
808
815
  if (wi._prUrl) arts.prUrl = wi._prUrl;
809
- if (_artNotes.length > 0) arts.notes = _artNotes;
816
+ if (_artNotes.length > 0) arts.notes = _artNotes.map(n => ({ id: n.id, file: n.file }));
810
817
  // Track plan/PRD artifacts from dispatch metadata
811
818
  if (dispatchItem.meta.item?.planFile) arts.plan = dispatchItem.meta.item.planFile;
812
819
  if (dispatchItem.meta.item?._prdFilename) arts.prd = dispatchItem.meta.item._prdFilename;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.646",
3
+ "version": "0.1.647",
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"