@yemi33/minions 0.1.2239 → 0.1.2240
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/engine/shared.js +46 -16
- package/engine.js +49 -8
- package/package.json +1 -1
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,32 @@ 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
|
+
|
|
5640
5669
|
// ── Spawn cwd vs worktree placement (W-mp73x32w000l143d) ──────────────────────
|
|
5641
5670
|
// Work types that don't need a git worktree — they read repo state but don't
|
|
5642
5671
|
// produce code changes. Centralized here so engine.js spawnAgent and any
|
|
@@ -8931,6 +8960,7 @@ module.exports = {
|
|
|
8931
8960
|
parseWorktreePorcelain,
|
|
8932
8961
|
assertWorktreeOutsideProject,
|
|
8933
8962
|
resolveProjectRootDir,
|
|
8963
|
+
resolveAgentCopilotHome,
|
|
8934
8964
|
resolveSpawnPaths,
|
|
8935
8965
|
validateWorkItemWorkdir,
|
|
8936
8966
|
applyWorkdir,
|
package/engine.js
CHANGED
|
@@ -1886,6 +1886,50 @@ 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
|
+
try {
|
|
1911
|
+
const home = shared.resolveAgentCopilotHome(MINIONS_DIR);
|
|
1912
|
+
fs.mkdirSync(home, { recursive: true });
|
|
1913
|
+
const disabled = new Set(shared.resolveCopilotAgentDisabledMcpServers(null, getConfig()?.engine));
|
|
1914
|
+
let servers = {};
|
|
1915
|
+
try {
|
|
1916
|
+
const userCfgPath = path.join(os.homedir(), '.copilot', 'mcp-config.json');
|
|
1917
|
+
const userCfg = JSON.parse(fs.readFileSync(userCfgPath, 'utf8').replace(/^/, ''));
|
|
1918
|
+
for (const [name, def] of Object.entries(userCfg.mcpServers || {})) {
|
|
1919
|
+
if (!disabled.has(name)) servers[name] = def;
|
|
1920
|
+
}
|
|
1921
|
+
} catch { servers = {}; /* no/unreadable user config → agents get no MCPs */ }
|
|
1922
|
+
// Write only when the content changes — keeps concurrent spawns from racing
|
|
1923
|
+
// on the shared file (the engine-level list is identical across agents).
|
|
1924
|
+
const desired = JSON.stringify({ mcpServers: servers }, null, 2);
|
|
1925
|
+
const cfgFile = path.join(home, 'mcp-config.json');
|
|
1926
|
+
let current = null;
|
|
1927
|
+
try { current = fs.readFileSync(cfgFile, 'utf8'); } catch {}
|
|
1928
|
+
if (current !== desired) fs.writeFileSync(cfgFile, desired);
|
|
1929
|
+
childEnv.COPILOT_HOME = home;
|
|
1930
|
+
} catch { /* leave inherited COPILOT_HOME untouched */ }
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1889
1933
|
async function spawnAgent(dispatchItem, config) {
|
|
1890
1934
|
const { id, agent: agentId, type, meta } = dispatchItem;
|
|
1891
1935
|
// Resolve prompt — prefers sidecar file when dispatchItem._promptFile is set
|
|
@@ -3579,12 +3623,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3579
3623
|
const resolvedModel = runtime.resolveModel(shared.resolveAgentModel(agentConfig, engineConfig));
|
|
3580
3624
|
const resolvedMaxBudget = shared.resolveAgentMaxBudget(agentConfig, engineConfig);
|
|
3581
3625
|
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
3626
|
// P-49e1c8b7 — hermetic harness opt-out (per-agent override allowed).
|
|
3589
3627
|
// When true, this dispatch:
|
|
3590
3628
|
// - skips Claude workspace .mcp.json pre-approval (preApproveWorkspaceMcps),
|
|
@@ -3648,7 +3686,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3648
3686
|
disableBuiltinMcps: engineConfig.copilotDisableBuiltinMcps,
|
|
3649
3687
|
suppressAgentsMd: engineConfig.copilotSuppressAgentsMd,
|
|
3650
3688
|
reasoningSummaries: engineConfig.copilotReasoningSummaries,
|
|
3651
|
-
disabledMcpServers: resolvedDisabledMcpServers,
|
|
3652
3689
|
});
|
|
3653
3690
|
|
|
3654
3691
|
// MCP servers: agents inherit from ~/.claude.json directly as Claude Code processes.
|
|
@@ -3725,6 +3762,9 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3725
3762
|
// random localhost port (blank window). Belt-and-suspenders with dashboard.js's
|
|
3726
3763
|
// stdout.isTTY gate.
|
|
3727
3764
|
childEnv.MINIONS_NO_AUTO_OPEN = '1';
|
|
3765
|
+
// MCP-free copilot config so agents never pop a per-spawn Microsoft auth
|
|
3766
|
+
// window — see _applyAgentCopilotHome / shared.resolveAgentCopilotHome.
|
|
3767
|
+
_applyAgentCopilotHome(childEnv);
|
|
3728
3768
|
|
|
3729
3769
|
if (getRepoHost(project) === 'ado') {
|
|
3730
3770
|
// Inject cached ADO token so ADO agents skip re-authentication (#998).
|
|
@@ -4205,7 +4245,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4205
4245
|
disableBuiltinMcps: engineConfig?.copilotDisableBuiltinMcps,
|
|
4206
4246
|
suppressAgentsMd: engineConfig?.copilotSuppressAgentsMd,
|
|
4207
4247
|
reasoningSummaries: engineConfig?.copilotReasoningSummaries,
|
|
4208
|
-
disabledMcpServers: resolvedDisabledMcpServers,
|
|
4209
4248
|
});
|
|
4210
4249
|
if (!resumeArgs.includes('--resume')) {
|
|
4211
4250
|
log('warn', `Steering: runtime ${runtime.name} did not accept session resume — skipping for ${agentId}`);
|
|
@@ -4236,6 +4275,8 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4236
4275
|
// W-mqef-dashboard-tty — same browser-popup suppression on steering resume
|
|
4237
4276
|
// (see the initial spawn site). Agents must never auto-open a browser.
|
|
4238
4277
|
childEnv.MINIONS_NO_AUTO_OPEN = '1';
|
|
4278
|
+
// Same MCP-free copilot home on steering resume (see the initial spawn site).
|
|
4279
|
+
_applyAgentCopilotHome(childEnv);
|
|
4239
4280
|
if (getRepoHost(project) === 'ado') {
|
|
4240
4281
|
// Inject cached ADO token for steering session too (#998)
|
|
4241
4282
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2240",
|
|
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"
|