@yemi33/minions 0.1.473 → 0.1.475
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 +11 -0
- package/dashboard.js +16 -6
- package/engine/lifecycle.js +9 -8
- package/engine/llm.js +25 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.475 (2026-04-07)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
- Fix unlocked metrics.json in lifecycle.js post-merge hook
|
|
7
|
+
- Fix unlocked metrics.json read-modify-write in trackEngineUsage
|
|
8
|
+
- Limit SSE initial live-stream payload to last 64KB
|
|
9
|
+
|
|
10
|
+
### Fixes
|
|
11
|
+
- add optional chaining for config.agents in updatePrAfterReview
|
|
12
|
+
- pass config to updatePrAfterReview to fix test failure
|
|
13
|
+
|
|
3
14
|
## 0.1.473 (2026-04-07)
|
|
4
15
|
|
|
5
16
|
### Fixes
|
package/dashboard.js
CHANGED
|
@@ -1511,15 +1511,25 @@ const server = http.createServer(async (req, res) => {
|
|
|
1511
1511
|
'Connection': 'keep-alive',
|
|
1512
1512
|
});
|
|
1513
1513
|
|
|
1514
|
-
// Send initial content
|
|
1514
|
+
// Send initial content — tail only (last 64KB by default) to avoid memory spikes
|
|
1515
|
+
const params = new URL(req.url, 'http://localhost').searchParams;
|
|
1516
|
+
const tailBytes = Math.max(0, parseInt(params.get('tail') || '65536', 10) || 65536);
|
|
1515
1517
|
let offset = 0;
|
|
1516
1518
|
try {
|
|
1517
|
-
const
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1519
|
+
const stat = fs.statSync(liveLogPath);
|
|
1520
|
+
const fileSize = stat.size;
|
|
1521
|
+
if (fileSize > 0) {
|
|
1522
|
+
const readStart = Math.max(0, fileSize - tailBytes);
|
|
1523
|
+
const readLen = fileSize - readStart;
|
|
1524
|
+
const fd = fs.openSync(liveLogPath, 'r');
|
|
1525
|
+
const buf = Buffer.alloc(readLen);
|
|
1526
|
+
fs.readSync(fd, buf, 0, readLen, readStart);
|
|
1527
|
+
fs.closeSync(fd);
|
|
1528
|
+
const content = buf.toString('utf8');
|
|
1529
|
+
if (content) safeWrite(`data: ${JSON.stringify(content)}\n\n`);
|
|
1530
|
+
offset = fileSize;
|
|
1521
1531
|
}
|
|
1522
|
-
} catch { /* optional */ }
|
|
1532
|
+
} catch { /* optional — file may not exist yet */ }
|
|
1523
1533
|
|
|
1524
1534
|
// Watch for changes using fs.watchFile (cross-platform, works on Windows)
|
|
1525
1535
|
const watcher = () => {
|
package/engine/lifecycle.js
CHANGED
|
@@ -712,12 +712,12 @@ function syncPrsFromOutput(output, agentId, meta, config) {
|
|
|
712
712
|
|
|
713
713
|
// ─── Post-Completion Hooks ──────────────────────────────────────────────────
|
|
714
714
|
|
|
715
|
-
function updatePrAfterReview(agentId, pr, project) {
|
|
715
|
+
function updatePrAfterReview(agentId, pr, project, config) {
|
|
716
716
|
|
|
717
717
|
if (!pr?.id) return;
|
|
718
718
|
|
|
719
|
-
|
|
720
|
-
const reviewerName = config.agents[agentId]?.name || agentId;
|
|
719
|
+
if (!config) config = getConfig();
|
|
720
|
+
const reviewerName = config.agents?.[agentId]?.name || agentId;
|
|
721
721
|
const dispatch = getDispatch();
|
|
722
722
|
const completedEntry = (dispatch.completed || []).find(d => d.agent === agentId && d.type === 'review');
|
|
723
723
|
|
|
@@ -853,10 +853,11 @@ async function handlePostMerge(pr, project, config, newStatus) {
|
|
|
853
853
|
const agentId = (pr.agent || '').toLowerCase();
|
|
854
854
|
if (agentId && config.agents?.[agentId]) {
|
|
855
855
|
const metricsPath = path.join(ENGINE_DIR, 'metrics.json');
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
856
|
+
mutateJsonFileLocked(metricsPath, (metrics) => {
|
|
857
|
+
if (!metrics[agentId]) metrics[agentId] = { tasksCompleted:0, tasksErrored:0, prsCreated:0, prsApproved:0, prsRejected:0, prsMerged:0, reviewsDone:0, lastTask:null, lastCompleted:null };
|
|
858
|
+
metrics[agentId].prsMerged = (metrics[agentId].prsMerged || 0) + 1;
|
|
859
|
+
return metrics;
|
|
860
|
+
});
|
|
860
861
|
}
|
|
861
862
|
|
|
862
863
|
const teamsUrl = process.env.TEAMS_PLAN_FLOW_URL;
|
|
@@ -1322,7 +1323,7 @@ function runPostCompletionHooks(dispatchItem, agentId, code, stdout, config) {
|
|
|
1322
1323
|
}
|
|
1323
1324
|
}
|
|
1324
1325
|
|
|
1325
|
-
if (type === WORK_TYPE.REVIEW) updatePrAfterReview(agentId, meta?.pr, meta?.project);
|
|
1326
|
+
if (type === WORK_TYPE.REVIEW) updatePrAfterReview(agentId, meta?.pr, meta?.project, config);
|
|
1326
1327
|
if (type === WORK_TYPE.FIX) updatePrAfterFix(meta?.pr, meta?.project, meta?.source);
|
|
1327
1328
|
checkForLearnings(agentId, config.agents[agentId], dispatchItem.task);
|
|
1328
1329
|
if (effectiveSuccess) {
|
package/engine/llm.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const shared = require('./shared');
|
|
8
|
-
const {
|
|
8
|
+
const { safeWrite, safeUnlink, uid, runFile, cleanChildEnv, parseStreamJsonOutput, mutateJsonFileLocked } = shared;
|
|
9
9
|
|
|
10
10
|
const MINIONS_DIR = path.resolve(__dirname, '..');
|
|
11
11
|
const ENGINE_DIR = __dirname;
|
|
@@ -14,31 +14,30 @@ function trackEngineUsage(category, usage) {
|
|
|
14
14
|
if (!usage) return;
|
|
15
15
|
try {
|
|
16
16
|
const metricsPath = path.join(ENGINE_DIR, 'metrics.json');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
metrics._engine[category]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
safeWrite(metricsPath, metrics);
|
|
17
|
+
mutateJsonFileLocked(metricsPath, (metrics) => {
|
|
18
|
+
if (!metrics._engine) metrics._engine = {};
|
|
19
|
+
if (!metrics._engine[category]) {
|
|
20
|
+
metrics._engine[category] = { calls: 0, costUsd: 0, inputTokens: 0, outputTokens: 0, cacheRead: 0, cacheCreation: 0 };
|
|
21
|
+
}
|
|
22
|
+
const cat = metrics._engine[category];
|
|
23
|
+
cat.calls++;
|
|
24
|
+
cat.costUsd += usage.costUsd || 0;
|
|
25
|
+
cat.inputTokens += usage.inputTokens || 0;
|
|
26
|
+
cat.outputTokens += usage.outputTokens || 0;
|
|
27
|
+
cat.cacheRead += usage.cacheRead || 0;
|
|
28
|
+
cat.cacheCreation = (cat.cacheCreation || 0) + (usage.cacheCreation || 0);
|
|
29
|
+
|
|
30
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
31
|
+
if (!metrics._daily) metrics._daily = {};
|
|
32
|
+
if (!metrics._daily[today]) metrics._daily[today] = { costUsd: 0, inputTokens: 0, outputTokens: 0, cacheRead: 0, tasks: 0 };
|
|
33
|
+
const daily = metrics._daily[today];
|
|
34
|
+
daily.costUsd += usage.costUsd || 0;
|
|
35
|
+
daily.inputTokens += usage.inputTokens || 0;
|
|
36
|
+
daily.outputTokens += usage.outputTokens || 0;
|
|
37
|
+
daily.cacheRead += usage.cacheRead || 0;
|
|
38
|
+
|
|
39
|
+
return metrics;
|
|
40
|
+
});
|
|
42
41
|
} catch (e) { console.error('metrics update:', e.message); }
|
|
43
42
|
}
|
|
44
43
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.475",
|
|
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"
|