@yemi33/minions 0.1.1696 → 0.1.1697
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 +2 -1
- package/dashboard.js +1 -1
- package/engine/cli.js +67 -5
- package/engine/copilot-models.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dashboard.js
CHANGED
|
@@ -5778,7 +5778,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5778
5778
|
const engine = getEngineState();
|
|
5779
5779
|
const agents = getAgents();
|
|
5780
5780
|
const health = {
|
|
5781
|
-
status: engine.state === 'running' ? 'healthy' : engine.state === 'paused' ? 'degraded' : 'stopped',
|
|
5781
|
+
status: engine.state === 'running' ? 'healthy' : (engine.state === 'paused' || engine.state === 'stopping') ? 'degraded' : 'stopped',
|
|
5782
5782
|
engine: { state: engine.state, pid: engine.pid },
|
|
5783
5783
|
agents: agents.map(a => ({ id: a.id, name: a.name, status: a.status })),
|
|
5784
5784
|
projects: PROJECTS.map(p => ({ name: p.name, reachable: fs.existsSync(p.localPath) })),
|
package/engine/cli.js
CHANGED
|
@@ -52,6 +52,43 @@ function isEngineProcessAlive(control) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
function createControlOwner(pid = process.pid) {
|
|
56
|
+
return { pid, ownerToken: `${pid}-${shared.uid()}` };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function controlBelongsToOwner(control, owner) {
|
|
60
|
+
return !!(
|
|
61
|
+
control &&
|
|
62
|
+
owner &&
|
|
63
|
+
owner.ownerToken &&
|
|
64
|
+
control.ownerToken === owner.ownerToken &&
|
|
65
|
+
control.pid === owner.pid
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function mutateControlForOwner(owner, mutator) {
|
|
70
|
+
let changed = false;
|
|
71
|
+
const control = mutateControl(current => {
|
|
72
|
+
if (!controlBelongsToOwner(current, owner)) return current;
|
|
73
|
+
changed = true;
|
|
74
|
+
return mutator(current);
|
|
75
|
+
});
|
|
76
|
+
return { changed, control };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function markControlStoppingForOwner(owner, stoppingAt) {
|
|
80
|
+
return mutateControlForOwner(owner, current => ({
|
|
81
|
+
...current,
|
|
82
|
+
state: 'stopping',
|
|
83
|
+
pid: owner.pid,
|
|
84
|
+
stopping_at: stoppingAt,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function markControlStoppedForOwner(owner, stoppedAt) {
|
|
89
|
+
return mutateControlForOwner(owner, () => ({ state: 'stopped', stopped_at: stoppedAt }));
|
|
90
|
+
}
|
|
91
|
+
|
|
55
92
|
function handleCommand(cmd, args) {
|
|
56
93
|
if (!cmd) {
|
|
57
94
|
return commands.start();
|
|
@@ -320,7 +357,15 @@ const commands = {
|
|
|
320
357
|
}
|
|
321
358
|
let codeCommit = null;
|
|
322
359
|
try { codeCommit = require('child_process').execSync('git rev-parse --short HEAD', { cwd: path.resolve(__dirname, '..'), encoding: 'utf8', timeout: 5000, windowsHide: true }).trim(); } catch {}
|
|
323
|
-
|
|
360
|
+
const controlOwner = createControlOwner();
|
|
361
|
+
mutateControl(() => ({
|
|
362
|
+
state: 'running',
|
|
363
|
+
pid: controlOwner.pid,
|
|
364
|
+
ownerToken: controlOwner.ownerToken,
|
|
365
|
+
started_at: e.ts(),
|
|
366
|
+
codeVersion,
|
|
367
|
+
codeCommit
|
|
368
|
+
}));
|
|
324
369
|
// Keep .minions-version in sync so `minions version` stays accurate after git pulls
|
|
325
370
|
if (codeVersion) {
|
|
326
371
|
try { fs.writeFileSync(path.join(shared.MINIONS_DIR, '.minions-version'), codeVersion); } catch {}
|
|
@@ -688,11 +733,18 @@ const commands = {
|
|
|
688
733
|
clearInterval(fastPollTimer);
|
|
689
734
|
if (teamsInboxTimer) clearInterval(teamsInboxTimer);
|
|
690
735
|
for (const f of _watchedFiles) { try { fs.unwatchFile(f); } catch { /* cleanup */ } }
|
|
691
|
-
|
|
736
|
+
const stoppingAt = e.ts();
|
|
737
|
+
const stoppingWrite = markControlStoppingForOwner(controlOwner, stoppingAt);
|
|
738
|
+
if (!stoppingWrite.changed) {
|
|
739
|
+
e.log('warn', 'Graceful shutdown skipped control.json stopping transition; control file is owned by a different engine process');
|
|
740
|
+
}
|
|
692
741
|
e.log('info', `Graceful shutdown initiated (${signal})`);
|
|
693
742
|
|
|
694
743
|
if (e.activeProcesses.size === 0) {
|
|
695
|
-
|
|
744
|
+
const stoppedWrite = markControlStoppedForOwner(controlOwner, e.ts());
|
|
745
|
+
if (!stoppedWrite.changed) {
|
|
746
|
+
e.log('warn', 'Graceful shutdown skipped control.json stopped transition; control file is owned by a different engine process');
|
|
747
|
+
}
|
|
696
748
|
e.log('info', 'Graceful shutdown complete (no active agents)');
|
|
697
749
|
shared.flushLogs(); // drain buffered log entries before exit
|
|
698
750
|
console.log('No active agents — stopped.');
|
|
@@ -706,7 +758,10 @@ const commands = {
|
|
|
706
758
|
const poll = setInterval(() => {
|
|
707
759
|
if (e.activeProcesses.size === 0) {
|
|
708
760
|
clearInterval(poll);
|
|
709
|
-
|
|
761
|
+
const stoppedWrite = markControlStoppedForOwner(controlOwner, e.ts());
|
|
762
|
+
if (!stoppedWrite.changed) {
|
|
763
|
+
e.log('warn', 'Graceful shutdown skipped control.json stopped transition; control file is owned by a different engine process');
|
|
764
|
+
}
|
|
710
765
|
e.log('info', 'Graceful shutdown complete (all agents finished)');
|
|
711
766
|
shared.flushLogs(); // drain buffered log entries before exit
|
|
712
767
|
console.log('All agents finished — stopped.');
|
|
@@ -714,7 +769,10 @@ const commands = {
|
|
|
714
769
|
}
|
|
715
770
|
if (Date.now() >= deadline) {
|
|
716
771
|
clearInterval(poll);
|
|
717
|
-
|
|
772
|
+
const stoppedWrite = markControlStoppedForOwner(controlOwner, e.ts());
|
|
773
|
+
if (!stoppedWrite.changed) {
|
|
774
|
+
e.log('warn', 'Graceful shutdown skipped control.json stopped transition; control file is owned by a different engine process');
|
|
775
|
+
}
|
|
718
776
|
e.log('warn', `Graceful shutdown timed out after ${timeout / 1000}s with ${e.activeProcesses.size} agent(s) still active`);
|
|
719
777
|
shared.flushLogs(); // drain buffered log entries before exit
|
|
720
778
|
console.log(`Shutdown timeout (${timeout / 1000}s) — force exiting with ${e.activeProcesses.size} agent(s) still running.`);
|
|
@@ -1374,4 +1432,8 @@ module.exports = {
|
|
|
1374
1432
|
_parseRuntimeFlags,
|
|
1375
1433
|
_modelLooksIncompatible,
|
|
1376
1434
|
_applyRuntimeFlags,
|
|
1435
|
+
_createControlOwner: createControlOwner,
|
|
1436
|
+
_controlBelongsToOwner: controlBelongsToOwner,
|
|
1437
|
+
_markControlStoppingForOwner: markControlStoppingForOwner,
|
|
1438
|
+
_markControlStoppedForOwner: markControlStoppedForOwner,
|
|
1377
1439
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1697",
|
|
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"
|