@yemi33/minions 0.1.1607 → 0.1.1609
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/cli.js +20 -5
- package/engine/dispatch.js +7 -5
- package/minions.js +40 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.1609 (2026-04-28)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
- auto-detect available CLI runtimes and pin engine.defaultCli
|
|
6
7
|
- match runtime tags to actual logos (pixel-crab Claude, mascot Copilot)
|
|
7
8
|
- replace runtime text tag with inline SVG logos
|
|
8
9
|
|
|
9
10
|
### Fixes
|
|
11
|
+
- kill agents from engine tmp pid files
|
|
10
12
|
- gate live completion banner on final process exit
|
|
11
13
|
- wrap CC Model input so its label/hint survive runtime hydration
|
|
12
14
|
- preserve reconnect stream state
|
package/engine/cli.js
CHANGED
|
@@ -1142,12 +1142,27 @@ const commands = {
|
|
|
1142
1142
|
const config = getConfig();
|
|
1143
1143
|
const shared = require('./shared');
|
|
1144
1144
|
|
|
1145
|
-
// Kill processes via PID files (expensive — outside dispatch lock)
|
|
1146
|
-
|
|
1145
|
+
// Kill processes via PID files (expensive — outside dispatch lock).
|
|
1146
|
+
// PID files live in engine/tmp/ (see engine/spawn-agent.js:220 — derived from
|
|
1147
|
+
// the prompt-<id>.md sidecar path that engine.js builds in engine/tmp/).
|
|
1148
|
+
// Reading from ENGINE_DIR directly is a no-op: spawn-agent never writes there.
|
|
1149
|
+
const pidDir = path.join(ENGINE_DIR, 'tmp');
|
|
1150
|
+
const pidFiles = shared.safeReadDir(pidDir).filter(f => f.startsWith('pid-') && f.endsWith('.pid'));
|
|
1147
1151
|
for (const f of pidFiles) {
|
|
1148
|
-
const
|
|
1149
|
-
|
|
1150
|
-
|
|
1152
|
+
const pidPath = path.join(pidDir, f);
|
|
1153
|
+
const raw = safeRead(pidPath).trim();
|
|
1154
|
+
// Guard against falsy/zero/NaN PIDs. Empty pid files would resolve to
|
|
1155
|
+
// Number('') === 0, and process.kill(0) on POSIX targets the entire
|
|
1156
|
+
// calling process group — which would kill the engine itself.
|
|
1157
|
+
let pidNum = NaN;
|
|
1158
|
+
try { pidNum = shared.validatePid(raw); } catch { /* invalid — skip */ }
|
|
1159
|
+
if (pidNum > 0) {
|
|
1160
|
+
try { process.kill(pidNum); console.log(`Killed process ${pidNum} (${f})`); }
|
|
1161
|
+
catch { console.log(`Process ${pidNum} already dead`); }
|
|
1162
|
+
} else {
|
|
1163
|
+
console.log(`Skipping ${f}: invalid or empty PID`);
|
|
1164
|
+
}
|
|
1165
|
+
try { fs.unlinkSync(pidPath); } catch { /* may not exist */ }
|
|
1151
1166
|
}
|
|
1152
1167
|
|
|
1153
1168
|
// Atomically read and clear dispatch.active (locked read-modify-write)
|
package/engine/dispatch.js
CHANGED
|
@@ -341,7 +341,7 @@ function cancelPendingDispatchesForPr(prId) {
|
|
|
341
341
|
*/
|
|
342
342
|
function cleanDispatchEntries(matchFn) {
|
|
343
343
|
const dispatchPath = path.join(MINIONS_DIR, 'engine', 'dispatch.json');
|
|
344
|
-
const
|
|
344
|
+
const tmpDir = path.join(MINIONS_DIR, 'engine', 'tmp');
|
|
345
345
|
let removed = 0;
|
|
346
346
|
const pidsToKill = [];
|
|
347
347
|
const filesToDelete = [];
|
|
@@ -353,15 +353,17 @@ function cleanDispatchEntries(matchFn) {
|
|
|
353
353
|
if (queue === 'active') {
|
|
354
354
|
for (const d of dispatch[queue]) {
|
|
355
355
|
if (!matchFn(d)) continue;
|
|
356
|
-
|
|
356
|
+
// PID files live in engine/tmp/ (see engine/spawn-agent.js:220 — derived
|
|
357
|
+
// from the prompt-<id>.md path that engine.js builds in engine/tmp/).
|
|
358
|
+
const pidFile = path.join(tmpDir, `pid-${d.id}.pid`);
|
|
357
359
|
try {
|
|
358
360
|
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim());
|
|
359
361
|
if (pid) pidsToKill.push(pid);
|
|
360
362
|
} catch { /* PID file may not exist */ }
|
|
361
363
|
filesToDelete.push(pidFile);
|
|
362
|
-
filesToDelete.push(path.join(
|
|
363
|
-
filesToDelete.push(path.join(
|
|
364
|
-
filesToDelete.push(path.join(
|
|
364
|
+
filesToDelete.push(path.join(tmpDir, `prompt-${d.id}.md`));
|
|
365
|
+
filesToDelete.push(path.join(tmpDir, `sysprompt-${d.id}.md`));
|
|
366
|
+
filesToDelete.push(path.join(tmpDir, `sysprompt-${d.id}.md.tmp`));
|
|
365
367
|
}
|
|
366
368
|
}
|
|
367
369
|
dispatch[queue] = dispatch[queue].filter(d => !matchFn(d));
|
package/minions.js
CHANGED
|
@@ -125,6 +125,30 @@ function autoDiscover(targetDir) {
|
|
|
125
125
|
|
|
126
126
|
// ─── Shared Helpers (used by both addProject and scanAndAdd) ─────────────────
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Probe each registered runtime adapter and return the names whose
|
|
130
|
+
* resolveBinary() returns a non-null result. Used by initMinions to set
|
|
131
|
+
* engine.defaultCli automatically. Adapter `resolveBinary()` returns `null`
|
|
132
|
+
* when the CLI binary isn't on PATH and otherwise returns `{ bin, ... }`.
|
|
133
|
+
* Errors (unregistered runtime, exec failures) are swallowed — the helper
|
|
134
|
+
* is best-effort and a missing CLI just means we don't pin defaultCli.
|
|
135
|
+
*/
|
|
136
|
+
function _detectAvailableRuntimes() {
|
|
137
|
+
const found = [];
|
|
138
|
+
let registry;
|
|
139
|
+
try { registry = require('./engine/runtimes'); }
|
|
140
|
+
catch { return found; }
|
|
141
|
+
for (const name of registry.listRuntimes()) {
|
|
142
|
+
try {
|
|
143
|
+
const adapter = registry.resolveRuntime(name);
|
|
144
|
+
if (typeof adapter.resolveBinary !== 'function') continue;
|
|
145
|
+
const result = adapter.resolveBinary({ env: process.env });
|
|
146
|
+
if (result && result.bin) found.push(name);
|
|
147
|
+
} catch { /* probe failed → treat as unavailable */ }
|
|
148
|
+
}
|
|
149
|
+
return found;
|
|
150
|
+
}
|
|
151
|
+
|
|
128
152
|
function buildPrUrlBase({ repoHost, org, project, repoName }) {
|
|
129
153
|
if (repoHost === 'github') {
|
|
130
154
|
return org && repoName ? `https://github.com/${org}/${repoName}/pull/` : '';
|
|
@@ -450,6 +474,22 @@ async function initMinions({ skipScan = false, scanRoot, scanDepth } = {}) {
|
|
|
450
474
|
if (!config.agents || Object.keys(config.agents).length === 0) {
|
|
451
475
|
config.agents = { ...DEFAULT_AGENTS };
|
|
452
476
|
}
|
|
477
|
+
|
|
478
|
+
// Auto-detect available runtime CLIs and pin engine.defaultCli to whichever
|
|
479
|
+
// is installed. Only set if the user hasn't already configured one — never
|
|
480
|
+
// overwrite an explicit choice on `init --force` upgrades.
|
|
481
|
+
if (!config.engine.defaultCli) {
|
|
482
|
+
const detected = _detectAvailableRuntimes();
|
|
483
|
+
if (detected.length === 1) {
|
|
484
|
+
config.engine.defaultCli = detected[0];
|
|
485
|
+
console.log(`\n ✓ Detected ${detected[0]} CLI — set as fleet default runtime`);
|
|
486
|
+
} else if (detected.length > 1) {
|
|
487
|
+
// Both available — prefer claude (the historical default and broader skill coverage)
|
|
488
|
+
config.engine.defaultCli = detected.includes('claude') ? 'claude' : detected[0];
|
|
489
|
+
console.log(`\n ✓ Detected ${detected.join(' + ')} — fleet default set to ${config.engine.defaultCli}`);
|
|
490
|
+
}
|
|
491
|
+
// If nothing detected, leave defaultCli unset (engine falls back to 'claude')
|
|
492
|
+
}
|
|
453
493
|
saveConfig(config);
|
|
454
494
|
console.log(`\n Minions initialized at ${MINIONS_HOME}`);
|
|
455
495
|
console.log(` Config, agents, and engine defaults created.\n`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1609",
|
|
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"
|