@yemi33/minions 0.1.646 → 0.1.648
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 +7 -1
- package/dashboard/js/render-work-items.js +4 -1
- package/engine/pipeline.js +1 -1
- package/engine/playbook.js +3 -0
- package/engine/shared.js +18 -3
- package/engine.js +10 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.648 (2026-04-09)
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
- use full slug for plan matching to prevent false-positive collisions
|
|
7
|
+
|
|
8
|
+
## 0.1.647 (2026-04-09)
|
|
4
9
|
|
|
5
10
|
### Features
|
|
11
|
+
- structured note IDs for inbox notes
|
|
6
12
|
- pipeline plan stage reconciliation and UX fixes
|
|
7
13
|
- track notes, plans, and PRDs as work item artifacts
|
|
8
14
|
|
|
@@ -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) {
|
|
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
|
|
package/engine/pipeline.js
CHANGED
|
@@ -305,7 +305,7 @@ function _findExistingPlanForMeeting(meetingIds, plansDir) {
|
|
|
305
305
|
if (mtg?.title) {
|
|
306
306
|
// Dashboard convention: "Meeting follow-up: {title}" → slug
|
|
307
307
|
const dashSlug = ('meeting-follow-up-' + mtg.title).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 50);
|
|
308
|
-
slugPrefixes.push(dashSlug
|
|
308
|
+
slugPrefixes.push(dashSlug);
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
let slugMatch = null;
|
package/engine/playbook.js
CHANGED
|
@@ -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,
|
|
297
|
-
return
|
|
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 {
|
|
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.
|
|
3
|
+
"version": "0.1.648",
|
|
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"
|