@yemi33/minions 0.1.2238 → 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/dashboard/js/command-center.js +25 -2
- package/dashboard/js/refresh.js +18 -3
- package/dashboard/js/render-other.js +19 -5
- package/dashboard/js/render-plans.js +8 -6
- package/dashboard/js/render-work-items.js +5 -3
- package/dashboard/js/utils.js +23 -13
- package/dashboard.js +2 -2
- package/docs/harness-transparency.md +6 -5
- package/docs/live-checkout-mode.md +37 -7
- package/engine/cli.js +26 -0
- package/engine/comment-classifier.js +1 -1
- package/engine/consolidation.js +119 -24
- package/engine/dispatch-store.js +27 -4
- package/engine/dispatch.js +1 -0
- package/engine/github.js +4 -1
- package/engine/live-checkout.js +292 -10
- package/engine/queries.js +115 -14
- package/engine/shared.js +49 -17
- package/engine/timeout.js +10 -1
- package/engine/watchdog.js +75 -0
- package/engine.js +202 -13
- package/package.json +1 -1
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
|
|
@@ -2257,10 +2301,15 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
2257
2301
|
// cwd = project.localPath, worktreeRootDir = null, liveMode = true.
|
|
2258
2302
|
// Instead of creating an engine-managed worktree we run prepareLiveCheckout
|
|
2259
2303
|
// in-place: it validates a clean tree and then checks out (or creates) the
|
|
2260
|
-
// target branch. On dirty refusal
|
|
2304
|
+
// target branch. On a CONFIRMED dirty refusal (the helper returns
|
|
2305
|
+
// { ok:false, reason:'dirty', dirtyFiles:[…] }) we write an inbox alert, stamp
|
|
2261
2306
|
// `_pendingReason: 'live_checkout_dirty'` on the WI, complete the dispatch
|
|
2262
2307
|
// non-retryably with FAILURE_CLASS.LIVE_CHECKOUT_DIRTY, and return — the
|
|
2263
|
-
// engine never runs `git reset`/`git clean` against the operator tree.
|
|
2308
|
+
// engine never runs `git reset`/`git clean` against the operator tree. If the
|
|
2309
|
+
// helper instead THROWS (guard/ref-validation/transient git error), that is
|
|
2310
|
+
// NOT proof of a dirty tree (#305): we complete with the separate
|
|
2311
|
+
// FAILURE_CLASS.LIVE_CHECKOUT_FAILED, which is retryable with bounded backoff
|
|
2312
|
+
// so racy branch-lock handoff or a transient git failure auto-recovers.
|
|
2264
2313
|
// On success we fall through; the worktree-creation block below is gated
|
|
2265
2314
|
// on `!liveMode`, so it never runs, and downstream cleanup paths
|
|
2266
2315
|
// (worktreePool.returnToPool, worktree-gc.gcDispatchWorktreeIfOrphan) are
|
|
@@ -2284,14 +2333,22 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
2284
2333
|
log: (msg, lvl) => log(lvl || 'info', msg),
|
|
2285
2334
|
});
|
|
2286
2335
|
} catch (liveErr) {
|
|
2287
|
-
|
|
2336
|
+
// #305: A THROWN helper/git error is NOT proof the worktree is dirty.
|
|
2337
|
+
// Classify it as LIVE_CHECKOUT_FAILED (transient/pre-spawn) and let the
|
|
2338
|
+
// dispatch retry path decide retryability via isRetryableFailureReason —
|
|
2339
|
+
// racy branch-lock handoff, a just-finished sibling dispatch, or a
|
|
2340
|
+
// transient `git status`/`rev-parse`/`checkout` failure usually clears on
|
|
2341
|
+
// the next attempt (bounded by ENGINE_DEFAULTS.maxRetries). Do NOT stamp
|
|
2342
|
+
// _pendingReason: 'live_checkout_dirty' or write a dirty-files alert here —
|
|
2343
|
+
// those belong to the confirmed-dirty result path below.
|
|
2344
|
+
log('error', `spawnAgent: live-checkout helper threw for ${id}: ${liveErr.message}`);
|
|
2288
2345
|
_cleanupPromptFiles();
|
|
2289
2346
|
completeDispatch(
|
|
2290
2347
|
id,
|
|
2291
2348
|
DISPATCH_RESULT.ERROR,
|
|
2292
2349
|
`live-checkout failed: ${liveErr.message}`.slice(0, 800),
|
|
2293
|
-
'Live-checkout helper threw before agent spawn
|
|
2294
|
-
{ failureClass: FAILURE_CLASS.
|
|
2350
|
+
'Live-checkout helper threw before agent spawn (not proof of a dirty tree). Auto-retried with bounded backoff; transient git/branch-lock state usually clears on the next attempt.',
|
|
2351
|
+
{ failureClass: FAILURE_CLASS.LIVE_CHECKOUT_FAILED },
|
|
2295
2352
|
);
|
|
2296
2353
|
cleanupTempAgent(agentId);
|
|
2297
2354
|
return null;
|
|
@@ -2342,7 +2399,96 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
2342
2399
|
cleanupTempAgent(agentId);
|
|
2343
2400
|
return null;
|
|
2344
2401
|
}
|
|
2402
|
+
// P-c5a1f3b8: mid-operation / detached-HEAD refusal. The tree is clean
|
|
2403
|
+
// (the dirty branch above already bailed) but the branch op cannot proceed
|
|
2404
|
+
// because the operator is mid-merge/rebase/cherry-pick/revert or sitting on
|
|
2405
|
+
// a detached HEAD. Distinct operator condition from `dirty` → distinct
|
|
2406
|
+
// FAILURE_CLASS (LIVE_CHECKOUT_MID_OPERATION) and distinct recovery
|
|
2407
|
+
// guidance. The engine NEVER runs git reset/clean/stash or aborts the
|
|
2408
|
+
// operator's in-progress operation — it refuses and tells the operator how
|
|
2409
|
+
// to recover with their own commands.
|
|
2410
|
+
if (_liveResult && _liveResult.ok === false
|
|
2411
|
+
&& (_liveResult.reason === 'mid-operation' || _liveResult.reason === 'detached-head')) {
|
|
2412
|
+
const _isMidOp = _liveResult.reason === 'mid-operation';
|
|
2413
|
+
const _op = _isMidOp ? (_liveResult.op || 'operation') : null;
|
|
2414
|
+
const _sha = _isMidOp ? null : (_liveResult.sha || '(unknown)');
|
|
2415
|
+
const _alertBody = [
|
|
2416
|
+
_isMidOp
|
|
2417
|
+
? '# Live-checkout blocked: in-progress git operation'
|
|
2418
|
+
: '# Live-checkout blocked: detached HEAD',
|
|
2419
|
+
'',
|
|
2420
|
+
`**Project:** ${project.name || '(unknown)'}`,
|
|
2421
|
+
`**Local path:** ${cwd}`,
|
|
2422
|
+
`**Branch:** ${branchName}`,
|
|
2423
|
+
`**Work item:** ${_wiIdForAlert}`,
|
|
2424
|
+
`**Dispatch:** ${id}`,
|
|
2425
|
+
'',
|
|
2426
|
+
_isMidOp
|
|
2427
|
+
? `The engine refused to spawn the agent because \`${cwd}\` has an in-progress **${_op}**. Live-checkout mode runs in your project directly — the engine never \`git reset\`, \`git clean\`, or aborts an operation in your tree.`
|
|
2428
|
+
: `The engine refused to spawn the agent because \`${cwd}\` is in a **detached-HEAD** state (HEAD at \`${_sha}\`). Branching off a detached HEAD would strand your anonymous commits, so the engine refuses rather than risk losing work.`,
|
|
2429
|
+
'',
|
|
2430
|
+
'## Recovery',
|
|
2431
|
+
'',
|
|
2432
|
+
_isMidOp
|
|
2433
|
+
? `Finish or abort the in-progress ${_op} with your own git commands (e.g. \`git ${_op} --continue\` or \`git ${_op} --abort\`), or checkout a branch, then re-dispatch the work item.`
|
|
2434
|
+
: 'Checkout a branch (e.g. `git checkout <branch>`) so HEAD points at a named ref, then re-dispatch the work item. If you have commits on the detached HEAD you want to keep, create a branch first (`git branch <name>`).',
|
|
2435
|
+
].join('\n');
|
|
2436
|
+
try { writeInboxAlert(`live-checkout-blocked-${_wiIdForAlert}`, _alertBody); }
|
|
2437
|
+
catch (e) { log('warn', `live-checkout: writeInboxAlert failed: ${e.message}`); }
|
|
2438
|
+
const _pendingReason = _isMidOp ? 'live_checkout_mid_operation' : 'live_checkout_detached_head';
|
|
2439
|
+
try {
|
|
2440
|
+
const _wiPath = resolveWorkItemPath(dispatchItem.meta);
|
|
2441
|
+
if (_wiPath && dispatchItem.meta?.item?.id) {
|
|
2442
|
+
mutateJsonFileLocked(_wiPath, (data) => {
|
|
2443
|
+
if (!Array.isArray(data)) return data;
|
|
2444
|
+
const wi = data.find(i => i && i.id === dispatchItem.meta.item.id);
|
|
2445
|
+
if (wi) wi._pendingReason = _pendingReason;
|
|
2446
|
+
return data;
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
} catch (e) { log('warn', `live-checkout: failed to stamp _pendingReason: ${e.message}`); }
|
|
2450
|
+
const _shortMsg = _isMidOp
|
|
2451
|
+
? `live-checkout blocked: in-progress ${_op} in ${cwd}`
|
|
2452
|
+
: `live-checkout blocked: detached HEAD (${_sha}) in ${cwd}`;
|
|
2453
|
+
const _guidance = _isMidOp
|
|
2454
|
+
? `Live-checkout mode cannot switch/create a branch while a ${_op} is in progress; the engine never aborts operator operations. Finish/abort the ${_op} or checkout a branch, then re-dispatch.`
|
|
2455
|
+
: 'Live-checkout mode cannot branch off a detached HEAD without risking operator commits; the engine never moves HEAD for you. Checkout a branch, then re-dispatch.';
|
|
2456
|
+
log('error', `spawnAgent: ${_shortMsg}`);
|
|
2457
|
+
_cleanupPromptFiles();
|
|
2458
|
+
completeDispatch(
|
|
2459
|
+
id,
|
|
2460
|
+
DISPATCH_RESULT.ERROR,
|
|
2461
|
+
_shortMsg.slice(0, 800),
|
|
2462
|
+
_guidance,
|
|
2463
|
+
{ failureClass: FAILURE_CLASS.LIVE_CHECKOUT_MID_OPERATION, agentRetryable: false },
|
|
2464
|
+
);
|
|
2465
|
+
cleanupTempAgent(agentId);
|
|
2466
|
+
return null;
|
|
2467
|
+
}
|
|
2345
2468
|
log('info', `live-checkout: ${_liveResult.created ? 'created' : 'switched to'} branch ${branchName} in ${cwd} (in-place; no worktree)`);
|
|
2469
|
+
// P-c5a1f3b8: persist the operator's original ref on the dispatch record so
|
|
2470
|
+
// the dispatch-end auto-restore (P-d9e6b2c4) can return the tree to where the
|
|
2471
|
+
// operator started — even after an engine restart + re-attach, where the
|
|
2472
|
+
// spawnAgent closure is gone and only the persisted dispatch record survives
|
|
2473
|
+
// (same pattern as resolveHarnessPropagated at engine/lifecycle.js:3576).
|
|
2474
|
+
if (_liveResult.originalRef) {
|
|
2475
|
+
dispatchItem.originalRef = _liveResult.originalRef;
|
|
2476
|
+
dispatchItem.originalRefType = _liveResult.originalRefType || 'branch';
|
|
2477
|
+
try {
|
|
2478
|
+
mutateDispatch((dispatch) => {
|
|
2479
|
+
for (const queue of ['pending', 'active', 'completed']) {
|
|
2480
|
+
const arr = Array.isArray(dispatch?.[queue]) ? dispatch[queue] : null;
|
|
2481
|
+
if (!arr) continue;
|
|
2482
|
+
const found = arr.find(d => d && d.id === id);
|
|
2483
|
+
if (found) {
|
|
2484
|
+
found.originalRef = _liveResult.originalRef;
|
|
2485
|
+
found.originalRefType = _liveResult.originalRefType || 'branch';
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
return dispatch;
|
|
2489
|
+
});
|
|
2490
|
+
} catch (e) { log('warn', `live-checkout: failed to persist originalRef for ${id}: ${e.message}`); }
|
|
2491
|
+
}
|
|
2346
2492
|
}
|
|
2347
2493
|
|
|
2348
2494
|
if (branchName && !liveMode) {
|
|
@@ -3477,12 +3623,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3477
3623
|
const resolvedModel = runtime.resolveModel(shared.resolveAgentModel(agentConfig, engineConfig));
|
|
3478
3624
|
const resolvedMaxBudget = shared.resolveAgentMaxBudget(agentConfig, engineConfig);
|
|
3479
3625
|
const resolvedBare = shared.resolveAgentBareMode(agentConfig, engineConfig);
|
|
3480
|
-
// P-mcp-storm (opg#134 backport) — user-scope MCP servers to keep out of
|
|
3481
|
-
// this agent dispatch. Copilot loads ~/.copilot/mcp-config.json
|
|
3482
|
-
// unconditionally; the adapter re-emits these as --disable-mcp-server <name>.
|
|
3483
|
-
// Other runtimes ignore the opt (their buildSpawnFlags don't read it), so no
|
|
3484
|
-
// runtime.name branch here.
|
|
3485
|
-
const resolvedDisabledMcpServers = shared.resolveCopilotAgentDisabledMcpServers(agentConfig, engineConfig);
|
|
3486
3626
|
// P-49e1c8b7 — hermetic harness opt-out (per-agent override allowed).
|
|
3487
3627
|
// When true, this dispatch:
|
|
3488
3628
|
// - skips Claude workspace .mcp.json pre-approval (preApproveWorkspaceMcps),
|
|
@@ -3546,7 +3686,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3546
3686
|
disableBuiltinMcps: engineConfig.copilotDisableBuiltinMcps,
|
|
3547
3687
|
suppressAgentsMd: engineConfig.copilotSuppressAgentsMd,
|
|
3548
3688
|
reasoningSummaries: engineConfig.copilotReasoningSummaries,
|
|
3549
|
-
disabledMcpServers: resolvedDisabledMcpServers,
|
|
3550
3689
|
});
|
|
3551
3690
|
|
|
3552
3691
|
// MCP servers: agents inherit from ~/.claude.json directly as Claude Code processes.
|
|
@@ -3623,6 +3762,9 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3623
3762
|
// random localhost port (blank window). Belt-and-suspenders with dashboard.js's
|
|
3624
3763
|
// stdout.isTTY gate.
|
|
3625
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);
|
|
3626
3768
|
|
|
3627
3769
|
if (getRepoHost(project) === 'ado') {
|
|
3628
3770
|
// Inject cached ADO token so ADO agents skip re-authentication (#998).
|
|
@@ -3814,6 +3956,15 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
3814
3956
|
}
|
|
3815
3957
|
|
|
3816
3958
|
_phaseT.spawnCallStart = Date.now();
|
|
3959
|
+
// P-c5a1f3b8 (Item D — live-mode push/PR-create cwd guard): in live mode
|
|
3960
|
+
// worktreePath stays null, so `cwd` here is project.localPath (it is never
|
|
3961
|
+
// reassigned to a worktree by the `if (worktreePath ...)` block above). The
|
|
3962
|
+
// agent's `git push -u origin <branch>` and PR-create therefore run in-place
|
|
3963
|
+
// against the operator's checkout. This cwd MUST NEVER be null for a mutating
|
|
3964
|
+
// live dispatch — shared.resolveSpawnPaths returns cwd === project.localPath
|
|
3965
|
+
// for live mode (regression-guarded in
|
|
3966
|
+
// test/unit/spawn-agent-live-mode-wiring.test.js). A null cwd would push from
|
|
3967
|
+
// the engine's own process dir and open the PR off the wrong tree.
|
|
3817
3968
|
// `detached: true` puts the agent in its own process group (POSIX) / job
|
|
3818
3969
|
// object (Windows), so when the engine dies — gracefully via stop, abruptly
|
|
3819
3970
|
// via taskkill, or because of a crash — the agent keeps running and can be
|
|
@@ -4094,7 +4245,6 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4094
4245
|
disableBuiltinMcps: engineConfig?.copilotDisableBuiltinMcps,
|
|
4095
4246
|
suppressAgentsMd: engineConfig?.copilotSuppressAgentsMd,
|
|
4096
4247
|
reasoningSummaries: engineConfig?.copilotReasoningSummaries,
|
|
4097
|
-
disabledMcpServers: resolvedDisabledMcpServers,
|
|
4098
4248
|
});
|
|
4099
4249
|
if (!resumeArgs.includes('--resume')) {
|
|
4100
4250
|
log('warn', `Steering: runtime ${runtime.name} did not accept session resume — skipping for ${agentId}`);
|
|
@@ -4125,6 +4275,8 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4125
4275
|
// W-mqef-dashboard-tty — same browser-popup suppression on steering resume
|
|
4126
4276
|
// (see the initial spawn site). Agents must never auto-open a browser.
|
|
4127
4277
|
childEnv.MINIONS_NO_AUTO_OPEN = '1';
|
|
4278
|
+
// Same MCP-free copilot home on steering resume (see the initial spawn site).
|
|
4279
|
+
_applyAgentCopilotHome(childEnv);
|
|
4128
4280
|
if (getRepoHost(project) === 'ado') {
|
|
4129
4281
|
// Inject cached ADO token for steering session too (#998)
|
|
4130
4282
|
try {
|
|
@@ -4946,6 +5098,43 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
4946
5098
|
}
|
|
4947
5099
|
}
|
|
4948
5100
|
|
|
5101
|
+
// ── P-d9e6b2c4 — live-mode dispatch-end auto-restore + terminal-failure
|
|
5102
|
+
// notify. Runs on EVERY terminal result for a live-mode dispatch: the
|
|
5103
|
+
// agent ran in-place in the operator's checkout, so switch the tree back
|
|
5104
|
+
// to the ref it was on before (see engine/live-checkout.js#
|
|
5105
|
+
// restoreLiveCheckoutAtDispatchEnd). The worktree-GC block above no-ops
|
|
5106
|
+
// in live mode (worktreePath===null); this is its live-mode counterpart.
|
|
5107
|
+
// originalRef was captured by prepareLiveCheckout and persisted on the
|
|
5108
|
+
// dispatch record at branch-resolution time (P-c5a1f3b8); the in-memory
|
|
5109
|
+
// closure copy is authoritative here. The engine-restart reattach path
|
|
5110
|
+
// fires the same helper from the persisted record in engine/cli.js. The
|
|
5111
|
+
// restore is a plain `git checkout <originalRef>` — never --force/reset/
|
|
5112
|
+
// clean/stash — and is best-effort: a thrown restore never alters the
|
|
5113
|
+
// dispatch result.
|
|
5114
|
+
if (liveMode && branchName) {
|
|
5115
|
+
try {
|
|
5116
|
+
const _liveRestore = require('./engine/live-checkout');
|
|
5117
|
+
await _liveRestore.restoreLiveCheckoutAtDispatchEnd({
|
|
5118
|
+
localPath: cwd,
|
|
5119
|
+
branchName,
|
|
5120
|
+
originalRef: dispatchItem.originalRef || '',
|
|
5121
|
+
originalRefType: dispatchItem.originalRefType || 'branch',
|
|
5122
|
+
dispatchId: id,
|
|
5123
|
+
projectName: project?.name,
|
|
5124
|
+
isTerminalFailure: effectiveResult !== DISPATCH_RESULT.SUCCESS,
|
|
5125
|
+
resultLabel: errorReason || effectiveResult,
|
|
5126
|
+
gitOpts: _gitOpts,
|
|
5127
|
+
log,
|
|
5128
|
+
writeInboxAlert,
|
|
5129
|
+
});
|
|
5130
|
+
} catch (restoreErr) {
|
|
5131
|
+
// restoreLiveCheckoutAtDispatchEnd swallows its own errors; this guard
|
|
5132
|
+
// is belt-and-suspenders so a require() hiccup can never break the
|
|
5133
|
+
// dispatch-completion path that follows.
|
|
5134
|
+
log('warn', `live-checkout: dispatch-end restore wiring threw for ${id}: ${restoreErr.message}`);
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
|
|
4949
5138
|
completeDispatch(id, effectiveResult, errorReason, resultSummary, completeOpts);
|
|
4950
5139
|
|
|
4951
5140
|
// W-mpbpexrg00110661 — surface managed-spawn partial-healthcheck failures
|
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"
|