@yemi33/minions 0.1.764 → 0.1.765
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 +5 -0
- package/dashboard.js +65 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dashboard.js
CHANGED
|
@@ -1459,6 +1459,70 @@ const server = http.createServer(async (req, res) => {
|
|
|
1459
1459
|
} catch (e) { return jsonReply(res, 400, { error: e.message }); }
|
|
1460
1460
|
}
|
|
1461
1461
|
|
|
1462
|
+
async function handleAgentKill(req, res, match) {
|
|
1463
|
+
try {
|
|
1464
|
+
const agentId = match[1].replace(/[^a-zA-Z0-9_-]/g, '');
|
|
1465
|
+
if (!agentId) return jsonReply(res, 400, { error: 'agent id required' });
|
|
1466
|
+
|
|
1467
|
+
const agentDir = path.join(MINIONS_DIR, 'agents', agentId);
|
|
1468
|
+
if (!fs.existsSync(agentDir)) return jsonReply(res, 404, { error: 'Agent not found' });
|
|
1469
|
+
|
|
1470
|
+
// 1. Kill process via pid file
|
|
1471
|
+
const pidPath = path.join(agentDir, 'pid');
|
|
1472
|
+
try {
|
|
1473
|
+
const pid = parseInt(shared.safeRead(pidPath) || '', 10);
|
|
1474
|
+
if (pid) {
|
|
1475
|
+
const safePid = shared.validatePid(pid);
|
|
1476
|
+
if (process.platform === 'win32') {
|
|
1477
|
+
require('child_process').execFileSync('taskkill', ['/PID', String(safePid), '/F', '/T'], { stdio: 'pipe', timeout: 5000, windowsHide: true });
|
|
1478
|
+
} else {
|
|
1479
|
+
process.kill(safePid, 'SIGTERM');
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
} catch { /* process already dead or no pid file */ }
|
|
1483
|
+
try { fs.unlinkSync(pidPath); } catch { /* optional */ }
|
|
1484
|
+
|
|
1485
|
+
// 2. Clear session.json so retry starts fresh
|
|
1486
|
+
try { fs.unlinkSync(path.join(agentDir, 'session.json')); } catch { /* optional */ }
|
|
1487
|
+
|
|
1488
|
+
// 3. Remove all active dispatch entries for this agent
|
|
1489
|
+
const dispatchPath = path.join(MINIONS_DIR, 'engine', 'dispatch.json');
|
|
1490
|
+
const removedIds = [];
|
|
1491
|
+
mutateJsonFileLocked(dispatchPath, (dp) => {
|
|
1492
|
+
const before = (dp.active || []).length;
|
|
1493
|
+
const removed = (dp.active || []).filter(d => d.agent === agentId);
|
|
1494
|
+
removed.forEach(d => removedIds.push(d.id));
|
|
1495
|
+
dp.active = (dp.active || []).filter(d => d.agent !== agentId);
|
|
1496
|
+
return dp;
|
|
1497
|
+
}, { defaultValue: { pending: [], active: [], completed: [] } });
|
|
1498
|
+
|
|
1499
|
+
// 4. Reset work items from dispatched → pending so they can be retried
|
|
1500
|
+
const allWiPaths = [];
|
|
1501
|
+
for (const proj of PROJECTS) allWiPaths.push(shared.projectWorkItemsPath(proj));
|
|
1502
|
+
let resetCount = 0;
|
|
1503
|
+
for (const wiPath of allWiPaths) {
|
|
1504
|
+
try {
|
|
1505
|
+
mutateWorkItems(wiPath, items => {
|
|
1506
|
+
for (const item of items) {
|
|
1507
|
+
if (item.dispatched_to === agentId && item.status === WI_STATUS.DISPATCHED) {
|
|
1508
|
+
item.status = WI_STATUS.PENDING;
|
|
1509
|
+
item._retryCount = (item._retryCount || 0) + 1;
|
|
1510
|
+
delete item.dispatched_at;
|
|
1511
|
+
delete item.dispatched_to;
|
|
1512
|
+
delete item._pendingReason;
|
|
1513
|
+
resetCount++;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
return items;
|
|
1517
|
+
});
|
|
1518
|
+
} catch { /* optional */ }
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
invalidateStatusCache();
|
|
1522
|
+
return jsonReply(res, 200, { ok: true, agent: agentId, dispatchCleared: removedIds.length, workItemsReset: resetCount });
|
|
1523
|
+
} catch (e) { return jsonReply(res, 400, { error: e.message }); }
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1462
1526
|
async function handleAgentsCancel(req, res) {
|
|
1463
1527
|
try {
|
|
1464
1528
|
const body = await readBody(req);
|
|
@@ -4027,6 +4091,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
4027
4091
|
return jsonReply(res, 200, { ok: true, message: 'Steering message sent' });
|
|
4028
4092
|
}},
|
|
4029
4093
|
{ method: 'POST', path: '/api/agents/cancel', desc: 'Cancel an active agent by ID or task substring', params: 'agent?, task?', handler: handleAgentsCancel },
|
|
4094
|
+
{ method: 'POST', path: /^\/api\/agent\/([\w-]+)\/kill$/, desc: 'Kill a running agent: stop process, clear dispatch, reset work items to pending', handler: handleAgentKill },
|
|
4030
4095
|
{ method: 'GET', path: /^\/api\/agent\/([\w-]+)\/live-stream(?:\?.*)?$/, desc: 'SSE real-time live output streaming', handler: handleAgentLiveStream },
|
|
4031
4096
|
{ method: 'GET', path: /^\/api\/agent\/([\w-]+)\/live(?:\?.*)?$/, desc: 'Tail live output for a working agent', params: 'tail? (bytes, default 8192)', handler: handleAgentLive },
|
|
4032
4097
|
{ method: 'GET', path: /^\/api\/agent\/([\w-]+)\/output(?:\?.*)?$/, desc: 'Fetch final output.log for an agent', handler: handleAgentOutput },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.765",
|
|
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"
|