@yemi33/minions 0.1.2239 → 0.1.2241
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/dashboard.js +8 -0
- package/engine/shared.js +81 -16
- package/engine.js +42 -8
- package/package.json +1 -1
package/dashboard.js
CHANGED
|
@@ -14178,6 +14178,14 @@ if (require.main === module) {
|
|
|
14178
14178
|
// engine reads, port binding) is captured rather than dying silently.
|
|
14179
14179
|
_installCrashHandlers();
|
|
14180
14180
|
|
|
14181
|
+
// Every copilot the dashboard spawns — Command Center, doc-chat, and the CC
|
|
14182
|
+
// worker pool (`copilot --acp`) — inherits this process's COPILOT_HOME. Point
|
|
14183
|
+
// it at the seeded, MCP-filtered home so those `direct:true` copilot calls
|
|
14184
|
+
// load the filtered config instead of the operator's full `~/.copilot` stack
|
|
14185
|
+
// (which would pop a Microsoft auth window per call). Mirrors the engine's
|
|
14186
|
+
// boot-time set. See shared.ensureAgentCopilotHome. Fail-open.
|
|
14187
|
+
try { process.env.COPILOT_HOME = shared.ensureAgentCopilotHome(MINIONS_DIR, CONFIG?.engine); } catch {}
|
|
14188
|
+
|
|
14181
14189
|
// Pre-warm the per-project git-status cache before accepting requests so
|
|
14182
14190
|
// the first /api/status after restart already returns gitState='ok' with a
|
|
14183
14191
|
// real branch instead of the ~8s pending gap that hides the projects-bar
|
package/engine/shared.js
CHANGED
|
@@ -2958,19 +2958,20 @@ const ENGINE_DEFAULTS = {
|
|
|
2958
2958
|
copilotSuppressAgentsMd: true, // Copilot --no-custom-instructions: stop AGENTS.md auto-load from fighting Minions playbook prompts
|
|
2959
2959
|
copilotStreamMode: 'on', // Copilot --stream <on|off>: 'on' streams assistant.message_delta events live; 'off' batches them
|
|
2960
2960
|
copilotReasoningSummaries: false, // Copilot --enable-reasoning-summaries (Anthropic-family models only)
|
|
2961
|
-
// P-mcp-storm — Copilot
|
|
2962
|
-
//
|
|
2963
|
-
//
|
|
2964
|
-
//
|
|
2965
|
-
//
|
|
2966
|
-
//
|
|
2967
|
-
//
|
|
2968
|
-
//
|
|
2969
|
-
//
|
|
2970
|
-
//
|
|
2971
|
-
//
|
|
2972
|
-
//
|
|
2973
|
-
//
|
|
2961
|
+
// P-mcp-storm — Copilot SPAWNS every server in its `mcp-config.json` on every
|
|
2962
|
+
// process start and authenticates it. `--disable-mcp-server <name>` only hides
|
|
2963
|
+
// a server's TOOLS from the model; it does NOT stop the server process (proven
|
|
2964
|
+
// empirically — agents spawned azmcp/workiq even with the flag set), so any
|
|
2965
|
+
// auth-requiring server pops a Microsoft sign-in window on EVERY agent spawn.
|
|
2966
|
+
// The ONLY real lever is the CONFIG: a server absent from the config can't be
|
|
2967
|
+
// spawned. The engine therefore points agents at a private COPILOT_HOME
|
|
2968
|
+
// (`shared.resolveAgentCopilotHome`) whose mcp-config is a copy of the operator's
|
|
2969
|
+
// `~/.copilot/mcp-config.json` MINUS the names in this list (see engine.js
|
|
2970
|
+
// `_applyAgentCopilotHome`). Default [] = inherit ALL of the operator's MCP
|
|
2971
|
+
// servers for agents (non-breaking). Add a name to disable it for agents only;
|
|
2972
|
+
// the operator's interactive `~/.copilot` is never touched. Per-agent override
|
|
2973
|
+
// `agent.copilotAgentDisabledMcpServers`. Resolved through
|
|
2974
|
+
// `shared.resolveCopilotAgentDisabledMcpServers(agent, engine)`.
|
|
2974
2975
|
copilotAgentDisabledMcpServers: [],
|
|
2975
2976
|
ccUseWorkerPool: false, // Sub-task C of W-mp2w003600196c51 (CC perf): when true AND CC runtime is copilot, _invokeCcStream routes through engine/cc-worker-pool.js (persistent `copilot --acp` per CC tab) instead of spawning a fresh CLI per turn. Off by default — opt-in feature flag. **Structurally copilot-only**: the pool spawns `copilot --acp` (Agent Client Protocol); Claude Code does not implement ACP, so resolveCcUseWorkerPool returns false on non-copilot CC runtimes even with explicit-true (W-mphlriic00095f69 — prevents silent runtime switch). Engine/agent dispatch path stays per-process regardless.
|
|
2976
2977
|
maxBudgetUsd: undefined, // fleet USD ceiling for --max-budget-usd (per-agent override: agents.<id>.maxBudgetUsd). Honors 0 via ?? so a literal cap of $0 works
|
|
@@ -3375,13 +3376,15 @@ function resolveAgentBareMode(agent, engine) {
|
|
|
3375
3376
|
}
|
|
3376
3377
|
|
|
3377
3378
|
// P-mcp-storm — Resolve the list of MCP server names to disable for spawned
|
|
3378
|
-
// Copilot agents
|
|
3379
|
+
// Copilot agents. The engine FILTERS these out of the agent's seeded
|
|
3380
|
+
// COPILOT_HOME mcp-config (engine.js `_applyAgentCopilotHome`) — a server absent
|
|
3381
|
+
// from the config can't be spawned, which is the only effective disable
|
|
3382
|
+
// (`--disable-mcp-server` does not stop the process). Chain: per-agent
|
|
3379
3383
|
// `agent.copilotAgentDisabledMcpServers` → `engine.copilotAgentDisabledMcpServers`
|
|
3380
3384
|
// → `[]` (inherit all). Tolerant of either an array OR a comma/whitespace-
|
|
3381
3385
|
// separated string (Settings UI / `MINIONS_*` env deliver strings). Always
|
|
3382
3386
|
// returns a deduped array of trimmed, non-empty strings. See ENGINE_DEFAULTS
|
|
3383
|
-
// for
|
|
3384
|
-
// `hermeticHarness` does NOT suppress it).
|
|
3387
|
+
// for the full rationale.
|
|
3385
3388
|
function _normalizeMcpServerList(v) {
|
|
3386
3389
|
if (v == null) return null;
|
|
3387
3390
|
const raw = Array.isArray(v) ? v : String(v).split(/[\s,]+/);
|
|
@@ -5637,6 +5640,66 @@ function resolveProjectRootDir(localPath, minionsDir) {
|
|
|
5637
5640
|
return fallback;
|
|
5638
5641
|
}
|
|
5639
5642
|
|
|
5643
|
+
/**
|
|
5644
|
+
* Resolve a stable, repo-EXTERNAL COPILOT_HOME for spawned copilot agents.
|
|
5645
|
+
*
|
|
5646
|
+
* Copilot loads `$COPILOT_HOME/mcp-config.json` and SPAWNS every server in it on
|
|
5647
|
+
* every process start. `--disable-mcp-server <name>` only hides a server's tools
|
|
5648
|
+
* from the model — it does NOT stop the server PROCESS from launching, so any
|
|
5649
|
+
* server that does interactive auth (azure-kusto/azmcp, DevBox, workiq, loop, …)
|
|
5650
|
+
* still pops a Microsoft sign-in window on EVERY agent spawn. With minions
|
|
5651
|
+
* spawning agents continuously that is an unbounded popup storm.
|
|
5652
|
+
*
|
|
5653
|
+
* The only effective lever is to give agents a COPILOT_HOME whose mcp-config has
|
|
5654
|
+
* NO user servers (the engine seeds `{"mcpServers":{}}` there). Copilot auth is
|
|
5655
|
+
* unaffected — it uses GH_TOKEN / the OS credential store, not files under the
|
|
5656
|
+
* home — and the operator's real `~/.copilot` (interactive copilot) is untouched.
|
|
5657
|
+
*
|
|
5658
|
+
* Placed on the MINIONS_DIR volume (copilot's session-store can grow to GBs, so
|
|
5659
|
+
* keep it off a possibly-full system drive) but OUTSIDE the repo, at the drive
|
|
5660
|
+
* root, so concurrent git branch switches in the working tree can never delete or
|
|
5661
|
+
* dirty it. Stable path so copilot session resume (`--resume`) stays consistent
|
|
5662
|
+
* across spawns. Falls back to the user home when no minionsDir is given.
|
|
5663
|
+
*/
|
|
5664
|
+
function resolveAgentCopilotHome(minionsDir) {
|
|
5665
|
+
const base = minionsDir ? path.parse(path.resolve(String(minionsDir))).root : os.homedir();
|
|
5666
|
+
return path.join(base, '.minions-agent-copilot-home');
|
|
5667
|
+
}
|
|
5668
|
+
|
|
5669
|
+
// Seed the agent COPILOT_HOME's mcp-config (copy of `~/.copilot/mcp-config.json`
|
|
5670
|
+
// MINUS `engine.copilotAgentDisabledMcpServers`) and return the home path. This
|
|
5671
|
+
// is the single source of truth for "what MCP servers may a minions-spawned
|
|
5672
|
+
// copilot load." It is applied to EVERY copilot spawn path — agent dispatches
|
|
5673
|
+
// (engine), internal `llm.callLLM` calls (engine), and CC / doc-chat / the CC
|
|
5674
|
+
// worker pool (dashboard) — by setting `process.env.COPILOT_HOME` at the boot of
|
|
5675
|
+
// both processes, so every copilot CHILD inherits the filtered config. copilot
|
|
5676
|
+
// SPAWNS every server in its config and authenticates it (`--disable-mcp-server`
|
|
5677
|
+
// only hides tools), so any auth-requiring server pops a Microsoft window per
|
|
5678
|
+
// spawn — filtering the config is the only effective control. Idempotent: writes
|
|
5679
|
+
// only when the content changes (safe under concurrent callers). The operator's
|
|
5680
|
+
// real `~/.copilot` (interactive copilot) is never touched. Fail-open.
|
|
5681
|
+
function ensureAgentCopilotHome(minionsDir, engine) {
|
|
5682
|
+
const home = resolveAgentCopilotHome(minionsDir);
|
|
5683
|
+
try {
|
|
5684
|
+
fs.mkdirSync(home, { recursive: true });
|
|
5685
|
+
const disabled = new Set(resolveCopilotAgentDisabledMcpServers(null, engine));
|
|
5686
|
+
let servers = {};
|
|
5687
|
+
try {
|
|
5688
|
+
const userCfgPath = path.join(os.homedir(), '.copilot', 'mcp-config.json');
|
|
5689
|
+
const userCfg = JSON.parse(fs.readFileSync(userCfgPath, 'utf8').replace(/^/, ''));
|
|
5690
|
+
for (const [name, def] of Object.entries(userCfg.mcpServers || {})) {
|
|
5691
|
+
if (!disabled.has(name)) servers[name] = def;
|
|
5692
|
+
}
|
|
5693
|
+
} catch { servers = {}; /* no/unreadable user config → no MCPs */ }
|
|
5694
|
+
const desired = JSON.stringify({ mcpServers: servers }, null, 2);
|
|
5695
|
+
const cfgFile = path.join(home, 'mcp-config.json');
|
|
5696
|
+
let current = null;
|
|
5697
|
+
try { current = fs.readFileSync(cfgFile, 'utf8'); } catch {}
|
|
5698
|
+
if (current !== desired) fs.writeFileSync(cfgFile, desired);
|
|
5699
|
+
} catch { /* fail-open: leave whatever home/config exists */ }
|
|
5700
|
+
return home;
|
|
5701
|
+
}
|
|
5702
|
+
|
|
5640
5703
|
// ── Spawn cwd vs worktree placement (W-mp73x32w000l143d) ──────────────────────
|
|
5641
5704
|
// Work types that don't need a git worktree — they read repo state but don't
|
|
5642
5705
|
// produce code changes. Centralized here so engine.js spawnAgent and any
|
|
@@ -8931,6 +8994,8 @@ module.exports = {
|
|
|
8931
8994
|
parseWorktreePorcelain,
|
|
8932
8995
|
assertWorktreeOutsideProject,
|
|
8933
8996
|
resolveProjectRootDir,
|
|
8997
|
+
resolveAgentCopilotHome,
|
|
8998
|
+
ensureAgentCopilotHome,
|
|
8934
8999
|
resolveSpawnPaths,
|
|
8935
9000
|
validateWorkItemWorkdir,
|
|
8936
9001
|
applyWorkdir,
|
package/engine.js
CHANGED
|
@@ -1886,6 +1886,35 @@ async function recoverPartialWorktree(rootDir, worktreePath, branchName, gitOpts
|
|
|
1886
1886
|
}
|
|
1887
1887
|
}
|
|
1888
1888
|
|
|
1889
|
+
// Seed a spawned agent's COPILOT_HOME mcp-config as a copy of the operator's
|
|
1890
|
+
// `~/.copilot/mcp-config.json` MINUS the servers in
|
|
1891
|
+
// `engine.copilotAgentDisabledMcpServers`, then point COPILOT_HOME at it.
|
|
1892
|
+
//
|
|
1893
|
+
// Why config-filtering and not `--disable-mcp-server`: copilot SPAWNS every
|
|
1894
|
+
// server in its config on startup and authenticates it; `--disable-mcp-server
|
|
1895
|
+
// <name>` only hides that server's TOOLS from the model, it does NOT stop the
|
|
1896
|
+
// server process. So any auth-requiring server (azure-kusto/azmcp, DevBox,
|
|
1897
|
+
// workiq, loop, teams…) pops a Microsoft sign-in window on EVERY agent spawn —
|
|
1898
|
+
// an unbounded popup storm at minions' spawn cadence. A server simply ABSENT
|
|
1899
|
+
// from the config can't be spawned, so filtering the config is the only real
|
|
1900
|
+
// disable lever.
|
|
1901
|
+
//
|
|
1902
|
+
// Default disabled list `[]` => agents inherit ALL of the operator's MCP servers
|
|
1903
|
+
// (non-breaking; matches interactive copilot). Add a name to disable it for
|
|
1904
|
+
// agents. COPILOT_HOME is copilot-specific; claude/codex ignore it, so this is
|
|
1905
|
+
// set unconditionally (no runtime.name branching, per the adapter contract).
|
|
1906
|
+
// Copilot auth is unaffected (GH_TOKEN / OS credential store); the operator's
|
|
1907
|
+
// real ~/.copilot is untouched. Best-effort/fail-open: any failure leaves the
|
|
1908
|
+
// inherited COPILOT_HOME so a hiccup never blocks a dispatch.
|
|
1909
|
+
function _applyAgentCopilotHome(childEnv) {
|
|
1910
|
+
// Re-seed (picks up Settings changes to the disabled list) + stamp the env.
|
|
1911
|
+
// process.env.COPILOT_HOME is also set at engine boot (see below) so the
|
|
1912
|
+
// child would inherit it anyway; this is belt-and-suspenders + keeps the
|
|
1913
|
+
// seed fresh per dispatch. See shared.ensureAgentCopilotHome.
|
|
1914
|
+
try { childEnv.COPILOT_HOME = shared.ensureAgentCopilotHome(MINIONS_DIR, getConfig()?.engine); }
|
|
1915
|
+
catch { /* leave inherited COPILOT_HOME untouched */ }
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1889
1918
|
async function spawnAgent(dispatchItem, config) {
|
|
1890
1919
|
const { id, agent: agentId, type, meta } = dispatchItem;
|
|
1891
1920
|
// Resolve prompt — prefers sidecar file when dispatchItem._promptFile is set
|
|
@@ -3579,12 +3608,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3579
3608
|
const resolvedModel = runtime.resolveModel(shared.resolveAgentModel(agentConfig, engineConfig));
|
|
3580
3609
|
const resolvedMaxBudget = shared.resolveAgentMaxBudget(agentConfig, engineConfig);
|
|
3581
3610
|
const resolvedBare = shared.resolveAgentBareMode(agentConfig, engineConfig);
|
|
3582
|
-
// P-mcp-storm (opg#134 backport) — user-scope MCP servers to keep out of
|
|
3583
|
-
// this agent dispatch. Copilot loads ~/.copilot/mcp-config.json
|
|
3584
|
-
// unconditionally; the adapter re-emits these as --disable-mcp-server <name>.
|
|
3585
|
-
// Other runtimes ignore the opt (their buildSpawnFlags don't read it), so no
|
|
3586
|
-
// runtime.name branch here.
|
|
3587
|
-
const resolvedDisabledMcpServers = shared.resolveCopilotAgentDisabledMcpServers(agentConfig, engineConfig);
|
|
3588
3611
|
// P-49e1c8b7 — hermetic harness opt-out (per-agent override allowed).
|
|
3589
3612
|
// When true, this dispatch:
|
|
3590
3613
|
// - skips Claude workspace .mcp.json pre-approval (preApproveWorkspaceMcps),
|
|
@@ -3648,7 +3671,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3648
3671
|
disableBuiltinMcps: engineConfig.copilotDisableBuiltinMcps,
|
|
3649
3672
|
suppressAgentsMd: engineConfig.copilotSuppressAgentsMd,
|
|
3650
3673
|
reasoningSummaries: engineConfig.copilotReasoningSummaries,
|
|
3651
|
-
disabledMcpServers: resolvedDisabledMcpServers,
|
|
3652
3674
|
});
|
|
3653
3675
|
|
|
3654
3676
|
// MCP servers: agents inherit from ~/.claude.json directly as Claude Code processes.
|
|
@@ -3725,6 +3747,9 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3725
3747
|
// random localhost port (blank window). Belt-and-suspenders with dashboard.js's
|
|
3726
3748
|
// stdout.isTTY gate.
|
|
3727
3749
|
childEnv.MINIONS_NO_AUTO_OPEN = '1';
|
|
3750
|
+
// MCP-free copilot config so agents never pop a per-spawn Microsoft auth
|
|
3751
|
+
// window — see _applyAgentCopilotHome / shared.resolveAgentCopilotHome.
|
|
3752
|
+
_applyAgentCopilotHome(childEnv);
|
|
3728
3753
|
|
|
3729
3754
|
if (getRepoHost(project) === 'ado') {
|
|
3730
3755
|
// Inject cached ADO token so ADO agents skip re-authentication (#998).
|
|
@@ -4205,7 +4230,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4205
4230
|
disableBuiltinMcps: engineConfig?.copilotDisableBuiltinMcps,
|
|
4206
4231
|
suppressAgentsMd: engineConfig?.copilotSuppressAgentsMd,
|
|
4207
4232
|
reasoningSummaries: engineConfig?.copilotReasoningSummaries,
|
|
4208
|
-
disabledMcpServers: resolvedDisabledMcpServers,
|
|
4209
4233
|
});
|
|
4210
4234
|
if (!resumeArgs.includes('--resume')) {
|
|
4211
4235
|
log('warn', `Steering: runtime ${runtime.name} did not accept session resume — skipping for ${agentId}`);
|
|
@@ -4236,6 +4260,8 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4236
4260
|
// W-mqef-dashboard-tty — same browser-popup suppression on steering resume
|
|
4237
4261
|
// (see the initial spawn site). Agents must never auto-open a browser.
|
|
4238
4262
|
childEnv.MINIONS_NO_AUTO_OPEN = '1';
|
|
4263
|
+
// Same MCP-free copilot home on steering resume (see the initial spawn site).
|
|
4264
|
+
_applyAgentCopilotHome(childEnv);
|
|
4239
4265
|
if (getRepoHost(project) === 'ado') {
|
|
4240
4266
|
// Inject cached ADO token for steering session too (#998)
|
|
4241
4267
|
try {
|
|
@@ -10232,6 +10258,14 @@ module.exports = {
|
|
|
10232
10258
|
// ─── Entrypoint ─────────────────────────────────────────────────────────────
|
|
10233
10259
|
|
|
10234
10260
|
if (require.main === module) {
|
|
10261
|
+
// Every copilot this process spawns — agent dispatches AND internal
|
|
10262
|
+
// `llm.callLLM` calls (consolidation, classification, meetings, …) — inherits
|
|
10263
|
+
// this process's COPILOT_HOME, so point it at the seeded, MCP-filtered home.
|
|
10264
|
+
// Without this, those `direct:true` copilot calls load the operator's full
|
|
10265
|
+
// `~/.copilot` stack and pop a Microsoft auth window per call. The dashboard
|
|
10266
|
+
// sets the same at its own boot for CC / doc-chat / the CC worker pool.
|
|
10267
|
+
// See shared.ensureAgentCopilotHome. Fail-open.
|
|
10268
|
+
try { process.env.COPILOT_HOME = shared.ensureAgentCopilotHome(MINIONS_DIR, getConfig()?.engine); } catch {}
|
|
10235
10269
|
const { handleCommand } = require('./engine/cli');
|
|
10236
10270
|
const [cmd, ...args] = process.argv.slice(2);
|
|
10237
10271
|
handleCommand(cmd, args);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2241",
|
|
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"
|