@yemi33/minions 0.1.1909 → 0.1.1910
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/README.md +2 -0
- package/engine/preflight.js +118 -1
- package/engine/runtimes/claude.js +9 -0
- package/engine/runtimes/copilot.js +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Inspired by and initially scaffolded from [Brady Gaster's Squad](https://bradyga
|
|
|
15
15
|
- **Anthropic API key** or Claude Max subscription (agents spawn Claude Code sessions)
|
|
16
16
|
- **Git** — agents create worktrees for all code changes
|
|
17
17
|
|
|
18
|
+
> **Note:** you do **not** need to configure your CLI for "autopilot" / "bypass permissions" / "dangerous mode". Minions passes the right bypass flag per spawn (`--dangerously-skip-permissions` for Claude; `--autopilot --allow-all --no-ask-user` for Copilot), independent of your global CLI config. Run `minions doctor` to verify your installed CLI accepts those flags.
|
|
19
|
+
|
|
18
20
|
## Installation
|
|
19
21
|
|
|
20
22
|
```bash
|
package/engine/preflight.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
|
-
const { execSync } = require('child_process');
|
|
13
|
+
const { execSync, execFileSync } = require('child_process');
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Resolve the Claude Code CLI binary path. Legacy helper preserved for back-
|
|
@@ -421,6 +421,115 @@ async function _modelDiscoveryResults(config) {
|
|
|
421
421
|
return results;
|
|
422
422
|
}
|
|
423
423
|
|
|
424
|
+
/**
|
|
425
|
+
* Spawn `<resolved.bin> --help` and return the combined stdout/stderr, or null
|
|
426
|
+
* if the binary couldn't be invoked at all. Used only by the bypass-flag check
|
|
427
|
+
* in `_bypassFlagResults`; never on the hot path of `runPreflight` because
|
|
428
|
+
* it adds a subprocess invocation per runtime.
|
|
429
|
+
*
|
|
430
|
+
* Many CLIs emit `--help` to stderr or return a non-zero code when invoked in
|
|
431
|
+
* a non-TTY context, so we tolerate both — `execFileSync` populates `stdout`
|
|
432
|
+
* and `stderr` on the thrown error and we read them back.
|
|
433
|
+
*/
|
|
434
|
+
function _fetchCliHelpText(resolved, { timeoutMs = 5000 } = {}) {
|
|
435
|
+
if (!resolved || !resolved.bin) return null;
|
|
436
|
+
const leading = Array.isArray(resolved.leadingArgs) ? resolved.leadingArgs : [];
|
|
437
|
+
let cmd;
|
|
438
|
+
let args;
|
|
439
|
+
if (resolved.native === false) {
|
|
440
|
+
// Node shim (e.g. claude/cli.js). Invoke via the current Node so we don't
|
|
441
|
+
// depend on a `node` on PATH and we honor the same execPath the engine
|
|
442
|
+
// uses for spawn-agent.
|
|
443
|
+
cmd = process.execPath;
|
|
444
|
+
args = [resolved.bin, ...leading, '--help'];
|
|
445
|
+
} else {
|
|
446
|
+
cmd = resolved.bin;
|
|
447
|
+
args = [...leading, '--help'];
|
|
448
|
+
}
|
|
449
|
+
try {
|
|
450
|
+
const out = execFileSync(cmd, args, {
|
|
451
|
+
encoding: 'utf8',
|
|
452
|
+
windowsHide: true,
|
|
453
|
+
timeout: timeoutMs,
|
|
454
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
455
|
+
});
|
|
456
|
+
return String(out || '');
|
|
457
|
+
} catch (e) {
|
|
458
|
+
const stdout = e && e.stdout ? String(e.stdout) : '';
|
|
459
|
+
const stderr = e && e.stderr ? String(e.stderr) : '';
|
|
460
|
+
const combined = stdout + stderr;
|
|
461
|
+
return combined.length > 0 ? combined : null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Pure helper — takes the adapter and the help text and returns a doctor
|
|
467
|
+
* result entry. Splitting this from the spawn keeps the helper unit-testable
|
|
468
|
+
* without mocking `execFileSync`. The check is `warn`-level (not critical) so
|
|
469
|
+
* a false positive from a CLI that renames flags or paginates help doesn't
|
|
470
|
+
* block existing installs; the engine spawns will still error loudly if the
|
|
471
|
+
* flag really isn't honored.
|
|
472
|
+
*/
|
|
473
|
+
function _checkBypassFlagSupported(runtimeName, adapter, helpText) {
|
|
474
|
+
const name = `Permission bypass: ${runtimeName}`;
|
|
475
|
+
const flags = Array.isArray(adapter && adapter.permissionBypassFlags)
|
|
476
|
+
? adapter.permissionBypassFlags.filter(f => typeof f === 'string' && f.length > 0)
|
|
477
|
+
: [];
|
|
478
|
+
if (flags.length === 0) {
|
|
479
|
+
return {
|
|
480
|
+
name,
|
|
481
|
+
ok: 'warn',
|
|
482
|
+
message: `adapter did not declare permissionBypassFlags — cannot verify ${runtimeName} CLI accepts headless bypass`,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
if (helpText == null || helpText === '') {
|
|
486
|
+
return {
|
|
487
|
+
name,
|
|
488
|
+
ok: 'warn',
|
|
489
|
+
message: `could not invoke ${runtimeName} --help to verify ${flags.join(' ')} support — Minions will still pass the flag(s) but you may see permission prompts if the CLI doesn't accept them`,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
const missing = flags.filter(f => !helpText.includes(f));
|
|
493
|
+
if (missing.length > 0) {
|
|
494
|
+
return {
|
|
495
|
+
name,
|
|
496
|
+
ok: 'warn',
|
|
497
|
+
message: `${runtimeName} --help does not list expected flag(s): ${missing.join(', ')} — your CLI may be outdated. Agents will hang on permission prompts. Update with the CLI's package manager (npm i -g @anthropic-ai/claude-code for Claude; winget upgrade Microsoft.CopilotCLI for Copilot)`,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
name,
|
|
502
|
+
ok: true,
|
|
503
|
+
message: `${flags.join(' ')} accepted`,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Build the per-runtime bypass-flag verification entries for `minions doctor`.
|
|
509
|
+
* One entry per distinct configured runtime. Skipped silently when the binary
|
|
510
|
+
* itself didn't resolve (the upstream `Runtime: <name>` check already surfaces
|
|
511
|
+
* that failure — no point shouting twice).
|
|
512
|
+
*/
|
|
513
|
+
function _bypassFlagResults(config) {
|
|
514
|
+
const results = [];
|
|
515
|
+
if (!config || typeof config !== 'object') return results;
|
|
516
|
+
let registry;
|
|
517
|
+
try { registry = require('./runtimes'); } catch { return results; }
|
|
518
|
+
const runtimes = _distinctRuntimes(config);
|
|
519
|
+
for (const runtimeName of runtimes) {
|
|
520
|
+
let adapter;
|
|
521
|
+
try { adapter = registry.resolveRuntime(runtimeName); }
|
|
522
|
+
catch { continue; }
|
|
523
|
+
let resolved = null;
|
|
524
|
+
try { resolved = adapter.resolveBinary({ env: process.env }); }
|
|
525
|
+
catch { /* upstream Runtime check already reported this */ }
|
|
526
|
+
if (!resolved || !resolved.bin) continue;
|
|
527
|
+
const helpText = _fetchCliHelpText(resolved);
|
|
528
|
+
results.push(_checkBypassFlagSupported(runtimeName, adapter, helpText));
|
|
529
|
+
}
|
|
530
|
+
return results;
|
|
531
|
+
}
|
|
532
|
+
|
|
424
533
|
/**
|
|
425
534
|
* Run extended doctor checks (preflight + runtime health + fleet summary +
|
|
426
535
|
* per-runtime model discovery).
|
|
@@ -552,6 +661,11 @@ function doctor(minionsHome) {
|
|
|
552
661
|
runtimeResults.push(...fleetSummary);
|
|
553
662
|
const modelResults = await _modelDiscoveryResults(preflightConfig);
|
|
554
663
|
runtimeResults.push(...modelResults);
|
|
664
|
+
// Verify each runtime CLI still recognizes the headless bypass flags the
|
|
665
|
+
// adapters inject. Catches "user installed an outdated CLI" before the
|
|
666
|
+
// first agent silently hangs on a permission prompt.
|
|
667
|
+
const bypassResults = _bypassFlagResults(preflightConfig);
|
|
668
|
+
runtimeResults.push(...bypassResults);
|
|
555
669
|
|
|
556
670
|
// Print all
|
|
557
671
|
const allResults = [...results, ...runtimeResults];
|
|
@@ -584,4 +698,7 @@ module.exports = {
|
|
|
584
698
|
_warmModelCache,
|
|
585
699
|
_fleetSummaryResults,
|
|
586
700
|
_modelDiscoveryResults,
|
|
701
|
+
_fetchCliHelpText,
|
|
702
|
+
_checkBypassFlagSupported,
|
|
703
|
+
_bypassFlagResults,
|
|
587
704
|
};
|
|
@@ -689,6 +689,14 @@ function createStreamConsumer(ctx) {
|
|
|
689
689
|
return { consume, reset };
|
|
690
690
|
}
|
|
691
691
|
|
|
692
|
+
// ── Permission Bypass ───────────────────────────────────────────────────────
|
|
693
|
+
//
|
|
694
|
+
// Flags the engine relies on for headless operation. `preflight.doctor()`
|
|
695
|
+
// shells out to `<bin> --help` and verifies each literal appears in the help
|
|
696
|
+
// text — surfaces "your CLI is too old / has been renamed" before agents
|
|
697
|
+
// silently hang on permission prompts. Must stay in sync with `buildArgs`.
|
|
698
|
+
const PERMISSION_BYPASS_FLAGS = ['--dangerously-skip-permissions'];
|
|
699
|
+
|
|
692
700
|
// ── Capability Block ────────────────────────────────────────────────────────
|
|
693
701
|
|
|
694
702
|
const capabilities = {
|
|
@@ -806,6 +814,7 @@ module.exports = {
|
|
|
806
814
|
parseStreamChunk,
|
|
807
815
|
parseError,
|
|
808
816
|
createStreamConsumer,
|
|
817
|
+
permissionBypassFlags: PERMISSION_BYPASS_FLAGS,
|
|
809
818
|
// Exposed for unit tests — never imported by engine code
|
|
810
819
|
_CLAUDE_SHORTHANDS,
|
|
811
820
|
THINKING_BLOCK_TYPES,
|
|
@@ -1062,6 +1062,14 @@ function createStreamConsumer(ctx) {
|
|
|
1062
1062
|
return { consume, reset };
|
|
1063
1063
|
}
|
|
1064
1064
|
|
|
1065
|
+
// ── Permission Bypass ───────────────────────────────────────────────────────
|
|
1066
|
+
//
|
|
1067
|
+
// Flags the engine relies on for headless operation. `preflight.doctor()`
|
|
1068
|
+
// shells out to `<bin> --help` and verifies each literal appears in the help
|
|
1069
|
+
// text — surfaces "your CLI is too old / has been renamed" before agents
|
|
1070
|
+
// silently hang on permission prompts. Must stay in sync with `buildArgs`.
|
|
1071
|
+
const PERMISSION_BYPASS_FLAGS = ['--autopilot', '--allow-all', '--no-ask-user'];
|
|
1072
|
+
|
|
1065
1073
|
// ── Capability Block ────────────────────────────────────────────────────────
|
|
1066
1074
|
|
|
1067
1075
|
const capabilities = {
|
|
@@ -1170,6 +1178,7 @@ module.exports = {
|
|
|
1170
1178
|
parseStreamChunk,
|
|
1171
1179
|
parseError,
|
|
1172
1180
|
createStreamConsumer,
|
|
1181
|
+
permissionBypassFlags: PERMISSION_BYPASS_FLAGS,
|
|
1173
1182
|
// Exposed for unit tests — engine code MUST go through resolveRuntime + the
|
|
1174
1183
|
// adapter contract; never reach into these helpers directly.
|
|
1175
1184
|
_MINIONS_MODEL_ALIASES,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1910",
|
|
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"
|