@yemi33/minions 0.1.2240 → 0.1.2242
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/bin/minions.js +9 -0
- package/dashboard.js +8 -0
- package/engine/shared.js +60 -0
- package/engine.js +37 -20
- package/package.json +1 -1
package/bin/minions.js
CHANGED
|
@@ -1358,6 +1358,15 @@ ${fs.existsSync(path.join(PKG_ROOT, '.git')) ? `
|
|
|
1358
1358
|
// Clear stale beacons AFTER the kill so the old dashboard's last writes
|
|
1359
1359
|
// can't repopulate the file in the gap between clear and shutdown.
|
|
1360
1360
|
_clearDashboardBrowserState(MINIONS_HOME);
|
|
1361
|
+
// Respawn-race guard: the watchdog (or a surviving supervisor) can spawn a
|
|
1362
|
+
// fresh engine/dashboard during the kill→spawn window — those become ORPHANS
|
|
1363
|
+
// the new stack never reaps, and orphan engines keep dispatching agents +
|
|
1364
|
+
// spawning copilot (the root of the recurring multi-engine / MCP-auth storms).
|
|
1365
|
+
// stop-intent is STILL set here, so any respawn has already stood down or is
|
|
1366
|
+
// about to; reap once more so the stack we spawn below is the ONLY one. Scoped
|
|
1367
|
+
// by command-line to engine/dashboard/supervisor — never touches agent/copilot
|
|
1368
|
+
// children, preserving the re-attach invariant.
|
|
1369
|
+
killMinionsProcesses(['engine.js', 'dashboard.js', 'supervisor.js']);
|
|
1361
1370
|
// Clear stop-intent so the freshly-spawned supervisor resumes guarding.
|
|
1362
1371
|
clearStopIntent();
|
|
1363
1372
|
spawnFullStackAndVerify({ rest, forceOpen, dashWasUp, restartStartMs });
|
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
|
@@ -5666,6 +5666,64 @@ function resolveAgentCopilotHome(minionsDir) {
|
|
|
5666
5666
|
return path.join(base, '.minions-agent-copilot-home');
|
|
5667
5667
|
}
|
|
5668
5668
|
|
|
5669
|
+
/**
|
|
5670
|
+
* Derive a scratch/temp base dir on the same volume agent work already lives on
|
|
5671
|
+
* — the configured worktree location (engine.worktreeRoot, default
|
|
5672
|
+
* `../worktrees`). Agents (copilot/node/git + JVM-based MCP servers) write heavy
|
|
5673
|
+
* temp under %TEMP% / $TMPDIR; when that resolves to a full system drive (e.g.
|
|
5674
|
+
* C:), operations thrash or fail and routinely overrun the CLI's per-command
|
|
5675
|
+
* timeout, surfacing to the operator as "Operation cancelled". Anchoring agent
|
|
5676
|
+
* temp next to the worktrees keeps scratch on the operator's work volume with NO
|
|
5677
|
+
* config knob and NO hardcoded path — it simply follows wherever worktrees
|
|
5678
|
+
* already go (a location the operator already placed off the system drive).
|
|
5679
|
+
*
|
|
5680
|
+
* Returns an absolute dir path, or null when no anchor can be resolved — callers
|
|
5681
|
+
* MUST treat null as "leave the inherited TEMP untouched" (fail-open).
|
|
5682
|
+
*/
|
|
5683
|
+
function resolveAgentTempBaseDir(project, engine, minionsDir) {
|
|
5684
|
+
let projectRoot;
|
|
5685
|
+
try { projectRoot = resolveProjectRootDir(project && project.localPath, minionsDir); }
|
|
5686
|
+
catch { return null; }
|
|
5687
|
+
const wtRel = (engine && engine.worktreeRoot) || ENGINE_DEFAULTS.worktreeRoot;
|
|
5688
|
+
let anchor;
|
|
5689
|
+
try { anchor = path.resolve(projectRoot, wtRel); } catch { return null; }
|
|
5690
|
+
return path.join(anchor, '.agent-temp');
|
|
5691
|
+
}
|
|
5692
|
+
|
|
5693
|
+
// Seed the agent COPILOT_HOME's mcp-config (copy of `~/.copilot/mcp-config.json`
|
|
5694
|
+
// MINUS `engine.copilotAgentDisabledMcpServers`) and return the home path. This
|
|
5695
|
+
// is the single source of truth for "what MCP servers may a minions-spawned
|
|
5696
|
+
// copilot load." It is applied to EVERY copilot spawn path — agent dispatches
|
|
5697
|
+
// (engine), internal `llm.callLLM` calls (engine), and CC / doc-chat / the CC
|
|
5698
|
+
// worker pool (dashboard) — by setting `process.env.COPILOT_HOME` at the boot of
|
|
5699
|
+
// both processes, so every copilot CHILD inherits the filtered config. copilot
|
|
5700
|
+
// SPAWNS every server in its config and authenticates it (`--disable-mcp-server`
|
|
5701
|
+
// only hides tools), so any auth-requiring server pops a Microsoft window per
|
|
5702
|
+
// spawn — filtering the config is the only effective control. Idempotent: writes
|
|
5703
|
+
// only when the content changes (safe under concurrent callers). The operator's
|
|
5704
|
+
// real `~/.copilot` (interactive copilot) is never touched. Fail-open.
|
|
5705
|
+
function ensureAgentCopilotHome(minionsDir, engine) {
|
|
5706
|
+
const home = resolveAgentCopilotHome(minionsDir);
|
|
5707
|
+
try {
|
|
5708
|
+
fs.mkdirSync(home, { recursive: true });
|
|
5709
|
+
const disabled = new Set(resolveCopilotAgentDisabledMcpServers(null, engine));
|
|
5710
|
+
let servers = {};
|
|
5711
|
+
try {
|
|
5712
|
+
const userCfgPath = path.join(os.homedir(), '.copilot', 'mcp-config.json');
|
|
5713
|
+
const userCfg = JSON.parse(fs.readFileSync(userCfgPath, 'utf8').replace(/^/, ''));
|
|
5714
|
+
for (const [name, def] of Object.entries(userCfg.mcpServers || {})) {
|
|
5715
|
+
if (!disabled.has(name)) servers[name] = def;
|
|
5716
|
+
}
|
|
5717
|
+
} catch { servers = {}; /* no/unreadable user config → no MCPs */ }
|
|
5718
|
+
const desired = JSON.stringify({ mcpServers: servers }, null, 2);
|
|
5719
|
+
const cfgFile = path.join(home, 'mcp-config.json');
|
|
5720
|
+
let current = null;
|
|
5721
|
+
try { current = fs.readFileSync(cfgFile, 'utf8'); } catch {}
|
|
5722
|
+
if (current !== desired) fs.writeFileSync(cfgFile, desired);
|
|
5723
|
+
} catch { /* fail-open: leave whatever home/config exists */ }
|
|
5724
|
+
return home;
|
|
5725
|
+
}
|
|
5726
|
+
|
|
5669
5727
|
// ── Spawn cwd vs worktree placement (W-mp73x32w000l143d) ──────────────────────
|
|
5670
5728
|
// Work types that don't need a git worktree — they read repo state but don't
|
|
5671
5729
|
// produce code changes. Centralized here so engine.js spawnAgent and any
|
|
@@ -8961,6 +9019,8 @@ module.exports = {
|
|
|
8961
9019
|
assertWorktreeOutsideProject,
|
|
8962
9020
|
resolveProjectRootDir,
|
|
8963
9021
|
resolveAgentCopilotHome,
|
|
9022
|
+
resolveAgentTempBaseDir,
|
|
9023
|
+
ensureAgentCopilotHome,
|
|
8964
9024
|
resolveSpawnPaths,
|
|
8965
9025
|
validateWorkItemWorkdir,
|
|
8966
9026
|
applyWorkdir,
|
package/engine.js
CHANGED
|
@@ -1907,27 +1907,31 @@ async function recoverPartialWorktree(rootDir, worktreePath, branchName, gitOpts
|
|
|
1907
1907
|
// real ~/.copilot is untouched. Best-effort/fail-open: any failure leaves the
|
|
1908
1908
|
// inherited COPILOT_HOME so a hiccup never blocks a dispatch.
|
|
1909
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
|
+
|
|
1918
|
+
// Point a spawned agent's TEMP/TMP/TMPDIR at a scratch dir on the worktree
|
|
1919
|
+
// volume instead of the (often full) system drive — see
|
|
1920
|
+
// shared.resolveAgentTempBaseDir. copilot/node/git + JVM-based MCP servers write
|
|
1921
|
+
// heavy temp there; on a full C: that thrashes and overruns the CLI's per-command
|
|
1922
|
+
// timeout ("Operation cancelled"). Best-effort + fail-open: any resolution/mkdir
|
|
1923
|
+
// failure leaves the inherited TEMP in place. Sets all three vars to cover
|
|
1924
|
+
// Windows (TEMP/TMP) and POSIX (TMPDIR).
|
|
1925
|
+
function _applyAgentTempEnv(childEnv, project) {
|
|
1910
1926
|
try {
|
|
1911
|
-
const
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
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 */ }
|
|
1927
|
+
const agentTmp = shared.resolveAgentTempBaseDir(project, getConfig()?.engine, MINIONS_DIR);
|
|
1928
|
+
if (agentTmp) {
|
|
1929
|
+
fs.mkdirSync(agentTmp, { recursive: true });
|
|
1930
|
+
childEnv.TEMP = agentTmp;
|
|
1931
|
+
childEnv.TMP = agentTmp;
|
|
1932
|
+
childEnv.TMPDIR = agentTmp;
|
|
1933
|
+
}
|
|
1934
|
+
} catch { /* leave inherited TEMP untouched */ }
|
|
1931
1935
|
}
|
|
1932
1936
|
|
|
1933
1937
|
async function spawnAgent(dispatchItem, config) {
|
|
@@ -3765,6 +3769,9 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3765
3769
|
// MCP-free copilot config so agents never pop a per-spawn Microsoft auth
|
|
3766
3770
|
// window — see _applyAgentCopilotHome / shared.resolveAgentCopilotHome.
|
|
3767
3771
|
_applyAgentCopilotHome(childEnv);
|
|
3772
|
+
// Keep agent scratch off a (possibly full) system drive — anchors TEMP/TMP to
|
|
3773
|
+
// the worktree volume. See _applyAgentTempEnv / shared.resolveAgentTempBaseDir.
|
|
3774
|
+
_applyAgentTempEnv(childEnv, project);
|
|
3768
3775
|
|
|
3769
3776
|
if (getRepoHost(project) === 'ado') {
|
|
3770
3777
|
// Inject cached ADO token so ADO agents skip re-authentication (#998).
|
|
@@ -4277,6 +4284,8 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4277
4284
|
childEnv.MINIONS_NO_AUTO_OPEN = '1';
|
|
4278
4285
|
// Same MCP-free copilot home on steering resume (see the initial spawn site).
|
|
4279
4286
|
_applyAgentCopilotHome(childEnv);
|
|
4287
|
+
// Same agent-scratch redirect on steering resume.
|
|
4288
|
+
_applyAgentTempEnv(childEnv, project);
|
|
4280
4289
|
if (getRepoHost(project) === 'ado') {
|
|
4281
4290
|
// Inject cached ADO token for steering session too (#998)
|
|
4282
4291
|
try {
|
|
@@ -10273,6 +10282,14 @@ module.exports = {
|
|
|
10273
10282
|
// ─── Entrypoint ─────────────────────────────────────────────────────────────
|
|
10274
10283
|
|
|
10275
10284
|
if (require.main === module) {
|
|
10285
|
+
// Every copilot this process spawns — agent dispatches AND internal
|
|
10286
|
+
// `llm.callLLM` calls (consolidation, classification, meetings, …) — inherits
|
|
10287
|
+
// this process's COPILOT_HOME, so point it at the seeded, MCP-filtered home.
|
|
10288
|
+
// Without this, those `direct:true` copilot calls load the operator's full
|
|
10289
|
+
// `~/.copilot` stack and pop a Microsoft auth window per call. The dashboard
|
|
10290
|
+
// sets the same at its own boot for CC / doc-chat / the CC worker pool.
|
|
10291
|
+
// See shared.ensureAgentCopilotHome. Fail-open.
|
|
10292
|
+
try { process.env.COPILOT_HOME = shared.ensureAgentCopilotHome(MINIONS_DIR, getConfig()?.engine); } catch {}
|
|
10276
10293
|
const { handleCommand } = require('./engine/cli');
|
|
10277
10294
|
const [cmd, ...args] = process.argv.slice(2);
|
|
10278
10295
|
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.2242",
|
|
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"
|