@yemi33/minions 0.1.102 → 0.1.104
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 +15 -0
- package/engine/lifecycle.js +34 -16
- package/engine/meeting.js +2 -4
- package/engine/shared.js +28 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.104 (2026-04-01)
|
|
4
|
+
|
|
5
|
+
### Engine
|
|
6
|
+
- engine/lifecycle.js
|
|
7
|
+
|
|
8
|
+
## 0.1.103 (2026-04-01)
|
|
9
|
+
|
|
10
|
+
### Engine
|
|
11
|
+
- engine/lifecycle.js
|
|
12
|
+
- engine/meeting.js
|
|
13
|
+
- engine/shared.js
|
|
14
|
+
|
|
15
|
+
### Other
|
|
16
|
+
- test/unit.test.js
|
|
17
|
+
|
|
3
18
|
## 0.1.102 (2026-04-01)
|
|
4
19
|
|
|
5
20
|
### Engine
|
package/engine/lifecycle.js
CHANGED
|
@@ -137,17 +137,10 @@ function checkPlanCompletion(meta, config) {
|
|
|
137
137
|
...uniquePrs.map(pr => `- ${pr.id}: ${pr.title || ''} ${pr.url || ''}`),
|
|
138
138
|
].filter(Boolean).join('\n');
|
|
139
139
|
|
|
140
|
-
// Write summary to notes/inbox (slug
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
const existing = safeReadDir(inboxDir).find(f => f.startsWith(`${summarySlug}-${dateStamp()}`));
|
|
145
|
-
if (!existing) {
|
|
146
|
-
shared.safeWrite(path.join(inboxDir, summaryFile), summary);
|
|
147
|
-
log('info', `PRD completion summary written to notes/inbox/${summaryFile}`);
|
|
148
|
-
} else {
|
|
149
|
-
log('info', `PRD completion summary already exists for today: ${existing}, skipping inbox write`);
|
|
150
|
-
}
|
|
140
|
+
// Write summary to notes/inbox (slug-based dedup prevents duplicates on same day)
|
|
141
|
+
const slug = `prd-completion-${planFile.replace('.json', '')}`;
|
|
142
|
+
const wrote = shared.writeToInbox('engine', slug, summary);
|
|
143
|
+
if (wrote) log('info', `PRD completion summary written to notes/inbox/`);
|
|
151
144
|
|
|
152
145
|
// Persist _completionNotified flag atomically BEFORE creating work items.
|
|
153
146
|
// This prevents duplicate inbox notes on re-entry. Work item creation below has its own
|
|
@@ -731,8 +724,15 @@ async function handlePostMerge(pr, project, config, newStatus) {
|
|
|
731
724
|
|
|
732
725
|
if (newStatus !== 'merged') return;
|
|
733
726
|
|
|
734
|
-
|
|
727
|
+
// Resolve linked work item from pr-links or PR branch name
|
|
728
|
+
let mergedItemId = getPrLinks()[pr.id];
|
|
729
|
+
if (!mergedItemId && pr.branch) {
|
|
730
|
+
const branchMatch = pr.branch.match(/(P-[a-z0-9]{6,})/i) || pr.branch.match(/(W-[a-z0-9]+)/i);
|
|
731
|
+
if (branchMatch) mergedItemId = branchMatch[1];
|
|
732
|
+
}
|
|
733
|
+
|
|
735
734
|
if (mergedItemId) {
|
|
735
|
+
// Mark PRD feature as implemented
|
|
736
736
|
const prdDir = path.join(MINIONS_DIR, 'prd');
|
|
737
737
|
try {
|
|
738
738
|
const planFiles = fs.readdirSync(prdDir).filter(f => f.endsWith('.json'));
|
|
@@ -749,6 +749,25 @@ async function handlePostMerge(pr, project, config, newStatus) {
|
|
|
749
749
|
}
|
|
750
750
|
if (updated > 0) log('info', `Post-merge: marked ${mergedItemId} as implemented for ${pr.id}`);
|
|
751
751
|
} catch (err) { log('warn', `Post-merge PRD update: ${err.message}`); }
|
|
752
|
+
|
|
753
|
+
// Mark work item as done
|
|
754
|
+
const wiPaths = [path.join(MINIONS_DIR, 'work-items.json')];
|
|
755
|
+
for (const p of shared.getProjects(config)) wiPaths.push(shared.projectWorkItemsPath(p));
|
|
756
|
+
for (const wiPath of wiPaths) {
|
|
757
|
+
try {
|
|
758
|
+
const items = safeJson(wiPath);
|
|
759
|
+
if (!items) continue;
|
|
760
|
+
const item = items.find(i => i.id === mergedItemId);
|
|
761
|
+
if (item && item.status !== 'done') {
|
|
762
|
+
log('info', `Post-merge: marking work item ${mergedItemId} as done (was ${item.status}) for ${pr.id}`);
|
|
763
|
+
item.status = 'done';
|
|
764
|
+
item.completedAt = e.ts();
|
|
765
|
+
item._mergedVia = pr.id;
|
|
766
|
+
shared.safeWrite(wiPath, items);
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
} catch (err) { log('warn', `Post-merge work item update: ${err.message}`); }
|
|
770
|
+
}
|
|
752
771
|
}
|
|
753
772
|
|
|
754
773
|
const agentId = (pr.agent || '').toLowerCase();
|
|
@@ -892,8 +911,7 @@ function createReviewFeedbackForAuthor(reviewerAgentId, pr, config) {
|
|
|
892
911
|
const reviewFiles = inboxFiles.filter(f => f.includes(reviewerAgentId) && f.includes(today));
|
|
893
912
|
if (reviewFiles.length === 0) return;
|
|
894
913
|
const reviewContent = reviewFiles.map(f => safeRead(path.join(INBOX_DIR, f))).join('\n\n');
|
|
895
|
-
const
|
|
896
|
-
const feedbackPath = shared.uniquePath(path.join(INBOX_DIR, feedbackFile));
|
|
914
|
+
const slug = `feedback-from-${reviewerAgentId}-${pr.id}`;
|
|
897
915
|
const content = `# Review Feedback for ${config.agents[authorAgentId]?.name || authorAgentId}\n\n` +
|
|
898
916
|
`**PR:** ${pr.id} — ${pr.title || ''}\n` +
|
|
899
917
|
`**Reviewer:** ${config.agents[reviewerAgentId]?.name || reviewerAgentId}\n` +
|
|
@@ -902,8 +920,8 @@ function createReviewFeedbackForAuthor(reviewerAgentId, pr, config) {
|
|
|
902
920
|
`## Action Required\n\nRead this feedback carefully. When you work on similar tasks in the future, ` +
|
|
903
921
|
`avoid the patterns flagged here. If you are assigned to fix this PR, ` +
|
|
904
922
|
`address every point raised above.\n`;
|
|
905
|
-
shared.
|
|
906
|
-
log('info', `Created review feedback for ${authorAgentId} from ${reviewerAgentId} on ${pr.id}`);
|
|
923
|
+
const wrote = shared.writeToInbox(authorAgentId, slug, content);
|
|
924
|
+
if (wrote) log('info', `Created review feedback for ${authorAgentId} from ${reviewerAgentId} on ${pr.id}`);
|
|
907
925
|
}
|
|
908
926
|
|
|
909
927
|
function updateMetrics(agentId, dispatchItem, result, taskUsage, prsCreatedCount, model) {
|
package/engine/meeting.js
CHANGED
|
@@ -206,15 +206,13 @@ function collectMeetingFindings(meetingId, agentId, roundName, output) {
|
|
|
206
206
|
meeting.status = 'completed';
|
|
207
207
|
meeting.completedAt = new Date().toISOString();
|
|
208
208
|
|
|
209
|
-
// Write transcript to inbox so agents learn from it
|
|
209
|
+
// Write transcript to inbox so agents learn from it (slug-based dedup)
|
|
210
210
|
const config = queries.getConfig();
|
|
211
211
|
const agents = config.agents || {};
|
|
212
212
|
const transcript = meeting.transcript.map(t =>
|
|
213
213
|
`### ${agents[t.agent]?.name || t.agent} (${t.type}, Round ${t.round})\n\n${t.content}`
|
|
214
214
|
).join('\n\n---\n\n');
|
|
215
|
-
|
|
216
|
-
`meeting-${meetingId}-${new Date().toISOString().slice(0, 10)}.md`);
|
|
217
|
-
safeWrite(inboxPath, `# Meeting Transcript: ${meeting.title}\n\n${transcript}`);
|
|
215
|
+
shared.writeToInbox('meeting', meetingId, `# Meeting Transcript: ${meeting.title}\n\n${transcript}`);
|
|
218
216
|
|
|
219
217
|
log('info', `Meeting ${meetingId} completed — transcript written to inbox`);
|
|
220
218
|
saveMeeting(meeting);
|
package/engine/shared.js
CHANGED
|
@@ -169,6 +169,33 @@ function uniquePath(filePath) {
|
|
|
169
169
|
return `${base}-${Date.now()}${ext}`;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
// ── Inbox Helpers ───────────────────────────────────────────────────────────
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Write a file to notes/inbox/ with slug+date-based dedup.
|
|
176
|
+
* Filename: `{agentId}-{slug}-{YYYY-MM-DD}.md`
|
|
177
|
+
* If a file with the same prefix already exists for today, skip the write.
|
|
178
|
+
* Pattern matches writeInboxAlert() in dispatch.js.
|
|
179
|
+
* @param {string} agentId - Agent or source identifier (e.g. 'engine', 'ralph')
|
|
180
|
+
* @param {string} slug - Short descriptive slug (e.g. 'prd-completion-plan1')
|
|
181
|
+
* @param {string} content - Markdown content to write
|
|
182
|
+
* @returns {boolean} true if a write occurred, false if deduped/skipped
|
|
183
|
+
*/
|
|
184
|
+
function writeToInbox(agentId, slug, content, _inboxDir) {
|
|
185
|
+
try {
|
|
186
|
+
const inboxDir = _inboxDir || path.join(MINIONS_DIR, 'notes', 'inbox');
|
|
187
|
+
const prefix = `${agentId}-${slug}-${dateStamp()}`;
|
|
188
|
+
const existing = safeReadDir(inboxDir).find(f => f.startsWith(prefix));
|
|
189
|
+
if (existing) return false;
|
|
190
|
+
const filePath = path.join(inboxDir, `${prefix}.md`);
|
|
191
|
+
safeWrite(filePath, content);
|
|
192
|
+
return true;
|
|
193
|
+
} catch (e) {
|
|
194
|
+
log('warn', `writeToInbox failed: ${e.message}`);
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
172
199
|
// ── Process Spawning ────────────────────────────────────────────────────────
|
|
173
200
|
// All child process calls go through these to ensure windowsHide: true
|
|
174
201
|
|
|
@@ -479,6 +506,7 @@ module.exports = {
|
|
|
479
506
|
mutateJsonFileLocked,
|
|
480
507
|
uid,
|
|
481
508
|
uniquePath,
|
|
509
|
+
writeToInbox,
|
|
482
510
|
exec,
|
|
483
511
|
execSilent,
|
|
484
512
|
run,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.104",
|
|
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"
|