@yemi33/minions 0.1.101 → 0.1.103
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 +18 -0
- package/engine/lifecycle.js +7 -15
- package/engine/meeting.js +2 -4
- package/engine/scheduler.js +2 -2
- package/engine/shared.js +28 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.103 (2026-04-01)
|
|
4
|
+
|
|
5
|
+
### Engine
|
|
6
|
+
- engine/lifecycle.js
|
|
7
|
+
- engine/meeting.js
|
|
8
|
+
- engine/shared.js
|
|
9
|
+
|
|
10
|
+
### Other
|
|
11
|
+
- test/unit.test.js
|
|
12
|
+
|
|
13
|
+
## 0.1.102 (2026-04-01)
|
|
14
|
+
|
|
15
|
+
### Engine
|
|
16
|
+
- engine/scheduler.js
|
|
17
|
+
|
|
18
|
+
### Other
|
|
19
|
+
- test/unit.test.js
|
|
20
|
+
|
|
3
21
|
## 0.1.101 (2026-04-01)
|
|
4
22
|
|
|
5
23
|
### 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
|
|
@@ -892,8 +885,7 @@ function createReviewFeedbackForAuthor(reviewerAgentId, pr, config) {
|
|
|
892
885
|
const reviewFiles = inboxFiles.filter(f => f.includes(reviewerAgentId) && f.includes(today));
|
|
893
886
|
if (reviewFiles.length === 0) return;
|
|
894
887
|
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));
|
|
888
|
+
const slug = `feedback-from-${reviewerAgentId}-${pr.id}`;
|
|
897
889
|
const content = `# Review Feedback for ${config.agents[authorAgentId]?.name || authorAgentId}\n\n` +
|
|
898
890
|
`**PR:** ${pr.id} — ${pr.title || ''}\n` +
|
|
899
891
|
`**Reviewer:** ${config.agents[reviewerAgentId]?.name || reviewerAgentId}\n` +
|
|
@@ -902,8 +894,8 @@ function createReviewFeedbackForAuthor(reviewerAgentId, pr, config) {
|
|
|
902
894
|
`## Action Required\n\nRead this feedback carefully. When you work on similar tasks in the future, ` +
|
|
903
895
|
`avoid the patterns flagged here. If you are assigned to fix this PR, ` +
|
|
904
896
|
`address every point raised above.\n`;
|
|
905
|
-
shared.
|
|
906
|
-
log('info', `Created review feedback for ${authorAgentId} from ${reviewerAgentId} on ${pr.id}`);
|
|
897
|
+
const wrote = shared.writeToInbox(authorAgentId, slug, content);
|
|
898
|
+
if (wrote) log('info', `Created review feedback for ${authorAgentId} from ${reviewerAgentId} on ${pr.id}`);
|
|
907
899
|
}
|
|
908
900
|
|
|
909
901
|
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/scheduler.js
CHANGED
|
@@ -61,11 +61,11 @@ function parseCronField(field, min, max) {
|
|
|
61
61
|
function parseCronExpr(expr) {
|
|
62
62
|
if (!expr || typeof expr !== 'string') return null;
|
|
63
63
|
const parts = expr.trim().split(/\s+/);
|
|
64
|
-
if (parts.length
|
|
64
|
+
if (parts.length !== 3) return null;
|
|
65
65
|
|
|
66
66
|
const minuteMatcher = parseCronField(parts[0], 0, 59);
|
|
67
67
|
const hourMatcher = parseCronField(parts[1], 0, 23);
|
|
68
|
-
const dowMatcher =
|
|
68
|
+
const dowMatcher = parseCronField(parts[2], 0, 6);
|
|
69
69
|
|
|
70
70
|
return {
|
|
71
71
|
matches(date) {
|
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.103",
|
|
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"
|