@yemi33/minions 0.1.415 → 0.1.416
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 +3 -1
- package/engine/consolidation.js +42 -36
- package/engine/dispatch.js +2 -2
- package/engine/queries.js +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.416 (2026-04-06)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
- Fix notes.md race condition and null guards in consolidation.js
|
|
7
|
+
- Replace 5 raw status strings with WI_STATUS constants
|
|
6
8
|
- Fix null crashes in lifecycle.js syncPrsFromOutput and createReviewFeedbackForAuthor
|
|
7
9
|
|
|
8
10
|
## 0.1.414 (2026-04-06)
|
package/engine/consolidation.js
CHANGED
|
@@ -38,7 +38,7 @@ function consolidateInbox(config) {
|
|
|
38
38
|
|
|
39
39
|
const items = files.map(f => ({
|
|
40
40
|
name: f,
|
|
41
|
-
content: safeRead(path.join(INBOX_DIR, f))
|
|
41
|
+
content: safeRead(path.join(INBOX_DIR, f)) || ''
|
|
42
42
|
}));
|
|
43
43
|
|
|
44
44
|
const existingNotes = getNotes() || '';
|
|
@@ -220,30 +220,33 @@ function consolidateWithLLM(items, existingNotes, files, config) {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
const entry = '\n\n---\n\n' + digest;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
223
|
+
// Wrap read-modify-write in file lock to prevent race with concurrent consolidation or manual edits
|
|
224
|
+
shared.withFileLock(NOTES_PATH + '.lock', () => {
|
|
225
|
+
const current = getNotes() || '';
|
|
226
|
+
let newContent = current + entry;
|
|
227
|
+
|
|
228
|
+
if (newContent.length > 50000) {
|
|
229
|
+
// Truncate on section boundary — scan backward for last \n# before byte limit
|
|
230
|
+
// Never cut mid-section to preserve readability
|
|
231
|
+
const limit = 50000;
|
|
232
|
+
const lastSectionBoundary = newContent.lastIndexOf('\n---\n\n### ', limit);
|
|
233
|
+
if (lastSectionBoundary > 0) {
|
|
234
|
+
newContent = newContent.slice(0, lastSectionBoundary);
|
|
235
|
+
log('info', `Pruned notes.md at section boundary (pos ${lastSectionBoundary}) to stay under ${limit} bytes`);
|
|
236
|
+
} else {
|
|
237
|
+
// Fallback: use the old section-count approach
|
|
238
|
+
const sections = newContent.split('\n---\n\n### ');
|
|
239
|
+
if (sections.length > 10) {
|
|
240
|
+
const header = sections[0];
|
|
241
|
+
const recent = sections.slice(-8);
|
|
242
|
+
newContent = header + '\n---\n\n### ' + recent.join('\n---\n\n### ');
|
|
243
|
+
log('info', `Pruned notes.md: removed ${sections.length - 9} old sections`);
|
|
244
|
+
}
|
|
242
245
|
}
|
|
243
246
|
}
|
|
244
|
-
}
|
|
245
247
|
|
|
246
|
-
|
|
248
|
+
safeWrite(NOTES_PATH, newContent);
|
|
249
|
+
});
|
|
247
250
|
classifyToKnowledgeBase(items);
|
|
248
251
|
archiveInboxFiles(files);
|
|
249
252
|
log('info', `LLM consolidation complete: ${files.length} notes processed by Haiku`);
|
|
@@ -297,10 +300,10 @@ function consolidateWithRegex(items, files) {
|
|
|
297
300
|
if (!trimmed || sectionPattern.test(trimmed)) continue;
|
|
298
301
|
let insight = null;
|
|
299
302
|
const numMatch = trimmed.match(numberedPattern);
|
|
300
|
-
if (numMatch) insight = `**${numMatch[1].trim()}**: ${numMatch[2].trim()}`;
|
|
303
|
+
if (numMatch && numMatch[1] && numMatch[2]) insight = `**${numMatch[1].trim()}**: ${numMatch[2].trim()}`;
|
|
301
304
|
if (!insight) {
|
|
302
305
|
const bulMatch = trimmed.match(bulletPattern);
|
|
303
|
-
if (bulMatch) insight = `**${bulMatch[1].trim()}**: ${bulMatch[2].trim()}`;
|
|
306
|
+
if (bulMatch && bulMatch[1] && bulMatch[2]) insight = `**${bulMatch[1].trim()}**: ${bulMatch[2].trim()}`;
|
|
304
307
|
}
|
|
305
308
|
if (!insight && importantKeywords.test(trimmed) && !trimmed.startsWith('#') && trimmed.length > 30 && trimmed.length < 500) {
|
|
306
309
|
insight = trimmed;
|
|
@@ -363,19 +366,22 @@ function consolidateWithRegex(items, files) {
|
|
|
363
366
|
const dupCount = allInsights.length - deduped.length;
|
|
364
367
|
if (dupCount > 0) entry += `_Deduplication: ${dupCount} duplicate(s) removed._\n`;
|
|
365
368
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
369
|
+
// Wrap read-modify-write in file lock to prevent race with concurrent consolidation or manual edits
|
|
370
|
+
shared.withFileLock(NOTES_PATH + '.lock', () => {
|
|
371
|
+
const current = getNotes() || '';
|
|
372
|
+
let newContent = current + entry;
|
|
373
|
+
if (newContent.length > 50000) {
|
|
374
|
+
const limit = 50000;
|
|
375
|
+
const lastBoundary = newContent.lastIndexOf('\n---\n\n### ', limit);
|
|
376
|
+
if (lastBoundary > 0) {
|
|
377
|
+
newContent = newContent.slice(0, lastBoundary);
|
|
378
|
+
} else {
|
|
379
|
+
const sections = newContent.split('\n---\n\n### ');
|
|
380
|
+
if (sections.length > 10) { newContent = sections[0] + '\n---\n\n### ' + sections.slice(-8).join('\n---\n\n### '); }
|
|
381
|
+
}
|
|
376
382
|
}
|
|
377
|
-
|
|
378
|
-
|
|
383
|
+
safeWrite(NOTES_PATH, newContent);
|
|
384
|
+
});
|
|
379
385
|
classifyToKnowledgeBase(items);
|
|
380
386
|
archiveInboxFiles(files);
|
|
381
387
|
log('info', `Regex fallback: consolidated ${files.length} notes \u2192 ${deduped.length} insights into notes.md`);
|
package/engine/dispatch.js
CHANGED
|
@@ -116,7 +116,7 @@ function completeDispatch(id, result = DISPATCH_RESULT.SUCCESS, reason = '', res
|
|
|
116
116
|
const maxRetries = ENGINE_DEFAULTS.maxRetries;
|
|
117
117
|
if (retryableFailure && retries < maxRetries) {
|
|
118
118
|
log('info', `Dispatch error for ${item.meta.item.id} — auto-retry ${retries + 1}/${maxRetries}`);
|
|
119
|
-
lifecycle().updateWorkItemStatus(item.meta,
|
|
119
|
+
lifecycle().updateWorkItemStatus(item.meta, WI_STATUS.PENDING, '');
|
|
120
120
|
// Remove this dispatch key from completed so dedupe doesn't block immediate redispatch.
|
|
121
121
|
if (item.meta?.dispatchKey) {
|
|
122
122
|
try {
|
|
@@ -150,7 +150,7 @@ function completeDispatch(id, result = DISPATCH_RESULT.SUCCESS, reason = '', res
|
|
|
150
150
|
const finalReason = !retryableFailure
|
|
151
151
|
? `Non-retryable failure: ${reason || 'Unknown error'}`
|
|
152
152
|
: (reason || `Failed after ${maxRetries} retries`);
|
|
153
|
-
lifecycle().updateWorkItemStatus(item.meta,
|
|
153
|
+
lifecycle().updateWorkItemStatus(item.meta, WI_STATUS.FAILED, finalReason);
|
|
154
154
|
// Alert: find items blocked by this failure and write inbox note
|
|
155
155
|
try {
|
|
156
156
|
const config = getConfig();
|
package/engine/queries.js
CHANGED
|
@@ -10,7 +10,8 @@ const os = require('os');
|
|
|
10
10
|
const shared = require('./shared');
|
|
11
11
|
|
|
12
12
|
const { safeRead, safeReadDir, safeJson, safeWrite, getProjects,
|
|
13
|
-
projectWorkItemsPath, projectPrPath, parseSkillFrontmatter, KB_CATEGORIES
|
|
13
|
+
projectWorkItemsPath, projectPrPath, parseSkillFrontmatter, KB_CATEGORIES,
|
|
14
|
+
WI_STATUS } = shared;
|
|
14
15
|
|
|
15
16
|
// ── Paths ───────────────────────────────────────────────────────────────────
|
|
16
17
|
|
|
@@ -179,7 +180,7 @@ function getAgentStatus(agentId) {
|
|
|
179
180
|
const latestInFlight = allItems
|
|
180
181
|
.filter(w =>
|
|
181
182
|
(w.dispatched_to || '').toLowerCase() === String(agentId).toLowerCase() &&
|
|
182
|
-
w.status ===
|
|
183
|
+
w.status === WI_STATUS.DISPATCHED
|
|
183
184
|
)
|
|
184
185
|
.sort((a, b) => (b.dispatched_at || '').localeCompare(a.dispatched_at || ''))[0];
|
|
185
186
|
if (latestInFlight) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.416",
|
|
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"
|