@yemi33/minions 0.1.1690 → 0.1.1692
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/CHANGELOG.md +8 -5
- package/README.md +4 -0
- package/engine/copilot-models.json +1 -1
- package/engine/llm.js +8 -9
- package/engine/playbook.js +21 -9
- package/engine/runtimes/copilot.js +1 -1
- package/engine/shared.js +6 -2
- package/engine/spawn-agent.js +11 -2
- package/engine/timeout.js +28 -7
- package/engine.js +34 -13
- package/package.json +1 -1
- package/playbooks/shared-rules.md +33 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.1692 (2026-05-04)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
-
-
|
|
6
|
+
- stop Azure auth for GitHub agents (#2005)
|
|
7
|
+
- recover stalled runtime resumes (#2004)
|
|
8
|
+
- preserve doc-chat response fragments (#2003)
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
## 0.1.1689 (2026-05-03)
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
- prefer az cli for ado tokens (#1996)
|
|
11
14
|
|
|
12
15
|
## 0.1.1688 (2026-05-02)
|
|
13
16
|
|
package/README.md
CHANGED
|
@@ -310,6 +310,10 @@ Agents inherit MCP servers directly from `~/.claude.json` as Claude Code process
|
|
|
310
310
|
|
|
311
311
|
Manually refresh with `minions mcp-sync`.
|
|
312
312
|
|
|
313
|
+
### GitHub Users
|
|
314
|
+
|
|
315
|
+
For GitHub repos, install and authenticate the [GitHub CLI](https://cli.github.com/). Agents should use `gh` for GitHub PR creation, PR lookup, comments, reviews, issues, and workflow checks. If GitHub or Copilot auth fails, refresh GitHub credentials with `gh auth status` and `gh auth login`, or provide `GH_TOKEN`/`COPILOT_GITHUB_TOKEN` from the environment. Azure DevOps authentication and tooling paths do not apply to GitHub repo work.
|
|
316
|
+
|
|
313
317
|
### Azure DevOps Users
|
|
314
318
|
|
|
315
319
|
For the best experience with ADO repos, install the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) with the Azure DevOps extension. Agents should use the `az` CLI first for Azure DevOps operations such as PR creation, PR lookup, comments, reviewers, work items, and pipelines. Use the Azure DevOps MCP fallback only when `az` is unavailable in the environment or insufficient for a specific action.
|
package/engine/llm.js
CHANGED
|
@@ -368,15 +368,13 @@ function _createStreamAccumulator({
|
|
|
368
368
|
if (ev) consumer.consume(ev);
|
|
369
369
|
}
|
|
370
370
|
if (!text && lastTaskCompleteSummary) text = lastTaskCompleteSummary;
|
|
371
|
-
// Reconciliation:
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (!sessionId && parsedTail.sessionId) sessionId = parsedTail.sessionId;
|
|
379
|
-
}
|
|
371
|
+
// Reconciliation: always let the runtime adapter re-parse the complete
|
|
372
|
+
// stdout. Stream consumers emit live progress, but parseOutput() owns the
|
|
373
|
+
// runtime-specific final answer shape (including multi-fragment messages).
|
|
374
|
+
const parsedTail = runtime.parseOutput(stdout, maxTextLength ? { maxTextLength } : {});
|
|
375
|
+
if (parsedTail.text) text = parsedTail.text;
|
|
376
|
+
if (!usage && parsedTail.usage) usage = parsedTail.usage;
|
|
377
|
+
if (!sessionId && parsedTail.sessionId) sessionId = parsedTail.sessionId;
|
|
380
378
|
return { text, usage, sessionId, raw: stdout, stderr, toolUses };
|
|
381
379
|
}
|
|
382
380
|
|
|
@@ -627,4 +625,5 @@ module.exports = {
|
|
|
627
625
|
_resolveModelFor,
|
|
628
626
|
_resolveModelForRuntime,
|
|
629
627
|
_resolveRuntimeFeatureOpts,
|
|
628
|
+
_createStreamAccumulator,
|
|
630
629
|
};
|
package/engine/playbook.js
CHANGED
|
@@ -407,16 +407,27 @@ function renderPlaybook(type, vars) {
|
|
|
407
407
|
const dispatchProject = (vars.repo_id && projects.find(p => p.repositoryId === vars.repo_id))
|
|
408
408
|
|| (vars.repo_name && projects.find(p => p.repoName === vars.repo_name))
|
|
409
409
|
|| projects[0] || {};
|
|
410
|
+
const renderProject = {
|
|
411
|
+
...dispatchProject,
|
|
412
|
+
adoOrg: vars.ado_org || vars.adoOrg || dispatchProject.adoOrg,
|
|
413
|
+
adoProject: vars.ado_project || vars.adoProject || dispatchProject.adoProject,
|
|
414
|
+
repoName: vars.repo_name || vars.repoName || dispatchProject.repoName,
|
|
415
|
+
repoHost: vars.repo_host || vars.repoHost || dispatchProject.repoHost,
|
|
416
|
+
};
|
|
417
|
+
const repoHost = getRepoHost(renderProject);
|
|
410
418
|
const projectVars = {
|
|
411
|
-
project_name:
|
|
412
|
-
ado_org:
|
|
413
|
-
ado_project:
|
|
414
|
-
repo_name:
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
419
|
+
project_name: renderProject.name || 'Unknown Project',
|
|
420
|
+
ado_org: renderProject.adoOrg || 'Unknown',
|
|
421
|
+
ado_project: renderProject.adoProject || 'Unknown',
|
|
422
|
+
repo_name: renderProject.repoName || 'Unknown',
|
|
423
|
+
repo_host: repoHost,
|
|
424
|
+
ado_shared_rules: repoHost === 'ado' ? '1' : '',
|
|
425
|
+
github_shared_rules: repoHost === 'github' ? '1' : '',
|
|
426
|
+
pr_create_instructions: getPrCreateInstructions(renderProject),
|
|
427
|
+
pr_comment_instructions: getPrCommentInstructions(renderProject),
|
|
428
|
+
pr_fetch_instructions: getPrFetchInstructions(renderProject),
|
|
429
|
+
pr_vote_instructions: getPrVoteInstructions(renderProject),
|
|
430
|
+
repo_host_label: getRepoHostLabel(renderProject),
|
|
420
431
|
};
|
|
421
432
|
const allVars = { ...projectVars, ...vars };
|
|
422
433
|
|
|
@@ -640,6 +651,7 @@ function buildBaseVars(agentId, config, project) {
|
|
|
640
651
|
ado_org: project?.adoOrg || 'Unknown',
|
|
641
652
|
ado_project: project?.adoProject || 'Unknown',
|
|
642
653
|
repo_name: project?.repoName || 'Unknown',
|
|
654
|
+
repo_host: getRepoHost(project),
|
|
643
655
|
main_branch: project?.mainBranch || 'main',
|
|
644
656
|
date: dateStamp(),
|
|
645
657
|
};
|
|
@@ -545,7 +545,7 @@ function parseError(rawOutput) {
|
|
|
545
545
|
const lower = text.toLowerCase();
|
|
546
546
|
|
|
547
547
|
if (/not authenticated|copilot login|please.*log.*in|401|403 forbidden|unauthorized/i.test(text)) {
|
|
548
|
-
return { message: 'Copilot authentication failed', code: 'auth-failure', retriable: false };
|
|
548
|
+
return { message: 'Copilot/GitHub authentication failed. Run `gh auth login` or provide GH_TOKEN/COPILOT_GITHUB_TOKEN with Copilot access.', code: 'auth-failure', retriable: false };
|
|
549
549
|
}
|
|
550
550
|
if (/rate limit|too many requests|\b429\b/i.test(text)) {
|
|
551
551
|
return { message: 'Copilot rate limit hit', code: 'rate-limit', retriable: true };
|
package/engine/shared.js
CHANGED
|
@@ -751,6 +751,7 @@ const ENGINE_DEFAULTS = {
|
|
|
751
751
|
inboxConsolidateThreshold: 5,
|
|
752
752
|
agentTimeout: 18000000, // 5h
|
|
753
753
|
heartbeatTimeout: 300000, // 5min — stale-orphan grace after process tracking is lost
|
|
754
|
+
resumeHeartbeatTimeout: 300000, // 5min — max wait for a resumed runtime to emit its first output
|
|
754
755
|
// Per-type stale-orphan overrides (merged with config.engine.heartbeatTimeouts at runtime — see timeout.js).
|
|
755
756
|
// Heavy work types (multi-file edits, builds, test suites, full verify cycles) routinely go quiet for
|
|
756
757
|
// longer than the 5-min default when the engine has lost their tracked handle (e.g. across an engine
|
|
@@ -1310,10 +1311,13 @@ function projectPrPath(project) {
|
|
|
1310
1311
|
}
|
|
1311
1312
|
|
|
1312
1313
|
function resolveProjectForPrPath(filePath, config = null) {
|
|
1313
|
-
const
|
|
1314
|
+
const resolvedPaths = new Set([path.resolve(filePath)]);
|
|
1315
|
+
if (filePath && !path.isAbsolute(filePath)) {
|
|
1316
|
+
resolvedPaths.add(path.resolve(MINIONS_DIR, filePath));
|
|
1317
|
+
}
|
|
1314
1318
|
const projects = getProjects(config);
|
|
1315
1319
|
for (const project of projects) {
|
|
1316
|
-
if (path.resolve(projectPrPath(project))
|
|
1320
|
+
if (resolvedPaths.has(path.resolve(projectPrPath(project)))) return project;
|
|
1317
1321
|
}
|
|
1318
1322
|
if (projects.length === 1) return projects[0];
|
|
1319
1323
|
return null;
|
package/engine/spawn-agent.js
CHANGED
|
@@ -129,6 +129,10 @@ function normalizeRuntimeExit(code, signal) {
|
|
|
129
129
|
return 1;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
function shouldInjectAdoTokenEnv(env = process.env) {
|
|
133
|
+
return String(env.MINIONS_REPO_HOST || '').trim().toLowerCase() === 'ado';
|
|
134
|
+
}
|
|
135
|
+
|
|
132
136
|
function injectAdoTokenEnv(env, { execSync: _execSync, acquireToken, warn = (msg) => process.stderr.write(msg + '\n') } = {}) {
|
|
133
137
|
let result;
|
|
134
138
|
try {
|
|
@@ -149,6 +153,11 @@ function injectAdoTokenEnv(env, { execSync: _execSync, acquireToken, warn = (msg
|
|
|
149
153
|
return true;
|
|
150
154
|
}
|
|
151
155
|
|
|
156
|
+
function injectAdoTokenEnvForRepoHost(env, opts) {
|
|
157
|
+
if (!shouldInjectAdoTokenEnv(env)) return false;
|
|
158
|
+
return injectAdoTokenEnv(env, opts);
|
|
159
|
+
}
|
|
160
|
+
|
|
152
161
|
const PROCESS_EXIT_SENTINEL_FLUSH_TIMEOUT_MS = 2000;
|
|
153
162
|
|
|
154
163
|
function formatProcessExitSentinel(exitCode, signal) {
|
|
@@ -251,7 +260,7 @@ function main() {
|
|
|
251
260
|
const { promptFile, sysPromptFile, runtimeName, opts, passthrough } = parsed;
|
|
252
261
|
|
|
253
262
|
const env = cleanChildEnv();
|
|
254
|
-
|
|
263
|
+
injectAdoTokenEnvForRepoHost(env);
|
|
255
264
|
|
|
256
265
|
let runtime;
|
|
257
266
|
try { runtime = resolveRuntime(runtimeName); }
|
|
@@ -399,6 +408,6 @@ function main() {
|
|
|
399
408
|
});
|
|
400
409
|
}
|
|
401
410
|
|
|
402
|
-
module.exports = { parseSpawnArgs, buildSpawnInvocation, normalizeRuntimeExit, injectAdoTokenEnv, writeProcessExitSentinel, computeAddDirs };
|
|
411
|
+
module.exports = { parseSpawnArgs, buildSpawnInvocation, normalizeRuntimeExit, shouldInjectAdoTokenEnv, injectAdoTokenEnv, injectAdoTokenEnvForRepoHost, writeProcessExitSentinel, computeAddDirs };
|
|
403
412
|
|
|
404
413
|
if (require.main === module) main();
|
package/engine/timeout.js
CHANGED
|
@@ -9,7 +9,7 @@ const queries = require('./queries');
|
|
|
9
9
|
const steering = require('./steering');
|
|
10
10
|
|
|
11
11
|
const { safeRead, safeWrite, safeJson, mutateJsonFileLocked, getProjects, projectWorkItemsPath, log, ts,
|
|
12
|
-
ENGINE_DEFAULTS, ENGINE_DIR, WI_STATUS, WORK_TYPE, DISPATCH_RESULT, AGENT_STATUS } = shared;
|
|
12
|
+
ENGINE_DEFAULTS, ENGINE_DIR, WI_STATUS, WORK_TYPE, DISPATCH_RESULT, AGENT_STATUS, FAILURE_CLASS } = shared;
|
|
13
13
|
const { getDispatch, getAgentStatus } = queries;
|
|
14
14
|
const AGENTS_DIR = queries.AGENTS_DIR;
|
|
15
15
|
const MINIONS_DIR = shared.MINIONS_DIR;
|
|
@@ -258,6 +258,7 @@ function checkTimeouts(config) {
|
|
|
258
258
|
|
|
259
259
|
const timeout = config.engine?.agentTimeout || ENGINE_DEFAULTS.agentTimeout;
|
|
260
260
|
const defaultStaleOrphanTimeout = config.engine?.heartbeatTimeout || ENGINE_DEFAULTS.heartbeatTimeout;
|
|
261
|
+
const runtimeResumeHeartbeatTimeout = config.engine?.resumeHeartbeatTimeout || ENGINE_DEFAULTS.resumeHeartbeatTimeout || defaultStaleOrphanTimeout;
|
|
261
262
|
|
|
262
263
|
// Optional per-type stale-orphan timeouts: merge ENGINE_DEFAULTS ← config overrides.
|
|
263
264
|
const perTypeStaleOrphanTimeouts = { ...ENGINE_DEFAULTS.heartbeatTimeouts, ...(config.engine?.heartbeatTimeouts || {}) };
|
|
@@ -274,8 +275,10 @@ function checkTimeouts(config) {
|
|
|
274
275
|
}
|
|
275
276
|
|
|
276
277
|
// 2. Stale-orphan check — for ALL active dispatch items (catches lost process handles after restart).
|
|
277
|
-
// Silence is not a failure for tracked live processes
|
|
278
|
-
// produce no stdout/stderr for extended periods.
|
|
278
|
+
// Silence is not a failure for tracked live processes once a runtime has emitted output:
|
|
279
|
+
// long CLI commands can legitimately produce no stdout/stderr for extended periods.
|
|
280
|
+
// The exception is a resumed runtime that has not produced its first stdout/stderr
|
|
281
|
+
// heartbeat after spawn; that is the "alive but stuck in --resume" failure mode.
|
|
279
282
|
const dispatchData = getDispatch();
|
|
280
283
|
const deadItems = [];
|
|
281
284
|
const legacyAnnotationClears = new Set();
|
|
@@ -332,8 +335,9 @@ function checkTimeouts(config) {
|
|
|
332
335
|
const liveLogPath = path.join(AGENTS_DIR, item.agent, 'live-output.log');
|
|
333
336
|
let lastActivity = item.started_at ? new Date(item.started_at).getTime() : 0;
|
|
334
337
|
|
|
335
|
-
// live-output.log mtime is
|
|
336
|
-
// It is not
|
|
338
|
+
// live-output.log mtime is used for stale-orphan cleanup, completion recovery,
|
|
339
|
+
// and the resume first-output watchdog. It is not a general output-silence
|
|
340
|
+
// timeout for live tracked processes.
|
|
337
341
|
try {
|
|
338
342
|
const stat = fs.statSync(liveLogPath);
|
|
339
343
|
lastActivity = Math.max(lastActivity, stat.mtimeMs);
|
|
@@ -394,6 +398,23 @@ function checkTimeouts(config) {
|
|
|
394
398
|
if (procInfo?._steeringAt && Date.now() - procInfo._steeringAt < 60000) continue;
|
|
395
399
|
|
|
396
400
|
if (processAlive) {
|
|
401
|
+
if (procInfo?._runtimeResumeAwaitingFirstOutput) {
|
|
402
|
+
const resumeStartedAt = Number(procInfo._runtimeResumeAt || 0);
|
|
403
|
+
const resumeHeartbeatAt = Math.max(lastActivity, resumeStartedAt);
|
|
404
|
+
const resumeSilentMs = Date.now() - resumeHeartbeatAt;
|
|
405
|
+
if (resumeSilentMs > runtimeResumeHeartbeatTimeout) {
|
|
406
|
+
const resumeSilentSec = Math.round(resumeSilentMs / 1000);
|
|
407
|
+
const reason = `Runtime resume stalled — no output heartbeat for ${resumeSilentSec}s`;
|
|
408
|
+
log('warn', `Runtime resume stalled: ${item.agent} (${item.id}) — no output heartbeat for ${resumeSilentSec}s; killing and retrying fresh`);
|
|
409
|
+
dispatch().updateAgentStatus(item.id, AGENT_STATUS.TIMED_OUT, reason);
|
|
410
|
+
try { fs.appendFileSync(liveLogPath, `\n[runtime-resume-timeout] ${reason}. Killing this resume attempt and retrying with a fresh session.\n`); } catch { /* optional */ }
|
|
411
|
+
// Clear the cached session so retry does not re-enter the same stuck --resume path.
|
|
412
|
+
try { shared.safeUnlink(path.join(AGENTS_DIR, item.agent, 'session.json')); } catch {}
|
|
413
|
+
activeProcesses.delete(item.id);
|
|
414
|
+
shared.killGracefully(procInfo.proc, 5000);
|
|
415
|
+
deadItems.push({ item, reason, failureClass: FAILURE_CLASS.TIMEOUT });
|
|
416
|
+
}
|
|
417
|
+
}
|
|
397
418
|
continue;
|
|
398
419
|
}
|
|
399
420
|
|
|
@@ -462,8 +483,8 @@ function checkTimeouts(config) {
|
|
|
462
483
|
}
|
|
463
484
|
|
|
464
485
|
// Clean up dead items
|
|
465
|
-
for (const { item, reason } of deadItems) {
|
|
466
|
-
completeDispatch(item.id, DISPATCH_RESULT.ERROR, reason);
|
|
486
|
+
for (const { item, reason, failureClass } of deadItems) {
|
|
487
|
+
completeDispatch(item.id, DISPATCH_RESULT.ERROR, reason, '', failureClass ? { failureClass } : {});
|
|
467
488
|
}
|
|
468
489
|
|
|
469
490
|
// Clear legacy blocking-tool annotations; process liveness no longer depends on tool parsing.
|
package/engine.js
CHANGED
|
@@ -135,7 +135,7 @@ const { getRouting, parseRoutingTable, getRoutingTableCached, getMonthlySpend,
|
|
|
135
135
|
const { renderPlaybook, validatePlaybookVars, PLAYBOOK_REQUIRED_VARS,
|
|
136
136
|
buildSystemPrompt, buildAgentContext, selectPlaybook,
|
|
137
137
|
buildBaseVars, buildPrDispatch, resolveTaskContext,
|
|
138
|
-
getRepoHostLabel, getRepoHostToolRule } = require('./engine/playbook');
|
|
138
|
+
getRepoHost, getRepoHostLabel, getRepoHostToolRule } = require('./engine/playbook');
|
|
139
139
|
|
|
140
140
|
// sanitizeBranch imported from shared.js
|
|
141
141
|
|
|
@@ -975,13 +975,16 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
975
975
|
// Spawn the claude process
|
|
976
976
|
const childEnv = shared.cleanChildEnv();
|
|
977
977
|
if (completionReportPath) childEnv.MINIONS_COMPLETION_REPORT = completionReportPath;
|
|
978
|
+
childEnv.MINIONS_REPO_HOST = getRepoHost(project);
|
|
978
979
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
980
|
+
if (getRepoHost(project) === 'ado') {
|
|
981
|
+
// Inject cached ADO token so ADO agents skip re-authentication (#998).
|
|
982
|
+
// getAdoToken() returns cached token (30-min TTL) or null — never blocks on browser auth.
|
|
983
|
+
try {
|
|
984
|
+
const adoToken = await getAdoToken();
|
|
985
|
+
if (adoToken) childEnv.MINIONS_ADO_TOKEN = adoToken;
|
|
986
|
+
} catch { /* non-fatal — agent can still authenticate on its own */ }
|
|
987
|
+
}
|
|
985
988
|
|
|
986
989
|
// Spawn via wrapper script — node directly (no bash intermediary)
|
|
987
990
|
// spawn-agent.js handles CLAUDECODE env cleanup and claude binary resolution
|
|
@@ -1052,6 +1055,10 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1052
1055
|
startedAt,
|
|
1053
1056
|
runtimeName,
|
|
1054
1057
|
sessionId: cachedSessionId,
|
|
1058
|
+
...(cachedSessionId ? {
|
|
1059
|
+
_runtimeResumeAt: Date.now(),
|
|
1060
|
+
_runtimeResumeAwaitingFirstOutput: true,
|
|
1061
|
+
} : {}),
|
|
1055
1062
|
_pendingSteeringFiles: pendingSteering.entries,
|
|
1056
1063
|
};
|
|
1057
1064
|
activeProcesses.set(id, initialProcInfo);
|
|
@@ -1063,6 +1070,12 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1063
1070
|
let _trustCheckDone = false;
|
|
1064
1071
|
const _spawnTime = Date.now();
|
|
1065
1072
|
|
|
1073
|
+
function markRuntimeResumeOutputSeen(procInfo) {
|
|
1074
|
+
if (!procInfo?._runtimeResumeAwaitingFirstOutput) return;
|
|
1075
|
+
procInfo._runtimeResumeAwaitingFirstOutput = false;
|
|
1076
|
+
procInfo.lastRealOutputAt = Date.now();
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1066
1079
|
proc.stdout.on('data', (data) => {
|
|
1067
1080
|
const chunk = data.toString();
|
|
1068
1081
|
realActivityMap.set(id, Date.now());
|
|
@@ -1086,6 +1099,7 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1086
1099
|
// Capture sessionId early for mid-session steering. Claude emits session_id;
|
|
1087
1100
|
// Copilot emits sessionId, so use the runtime-neutral steering helper.
|
|
1088
1101
|
const procInfo = activeProcesses.get(id);
|
|
1102
|
+
markRuntimeResumeOutputSeen(procInfo);
|
|
1089
1103
|
captureSessionIdFromStdoutChunk(agentId, id, branchName, runtime, procInfo, chunk, sessionCaptureState);
|
|
1090
1104
|
|
|
1091
1105
|
ackPendingSteeringFiles(agentId, procInfo, chunk);
|
|
@@ -1096,6 +1110,7 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1096
1110
|
realActivityMap.set(id, Date.now());
|
|
1097
1111
|
if (stderr.length < MAX_OUTPUT) stderr += chunk.slice(0, MAX_OUTPUT - stderr.length);
|
|
1098
1112
|
try { fs.appendFileSync(liveOutputPath, '[stderr] ' + chunk); } catch { /* optional */ }
|
|
1113
|
+
markRuntimeResumeOutputSeen(activeProcesses.get(id));
|
|
1099
1114
|
});
|
|
1100
1115
|
|
|
1101
1116
|
async function onAgentClose(code) {
|
|
@@ -1188,11 +1203,14 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1188
1203
|
const childEnv = shared.cleanChildEnv();
|
|
1189
1204
|
if (completionReportPath) childEnv.MINIONS_COMPLETION_REPORT = completionReportPath;
|
|
1190
1205
|
childEnv.MINIONS_LIVE_OUTPUT_PATH = liveOutputPath;
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1206
|
+
childEnv.MINIONS_REPO_HOST = getRepoHost(project);
|
|
1207
|
+
if (getRepoHost(project) === 'ado') {
|
|
1208
|
+
// Inject cached ADO token for steering session too (#998)
|
|
1209
|
+
try {
|
|
1210
|
+
const adoToken = await getAdoToken();
|
|
1211
|
+
if (adoToken) childEnv.MINIONS_ADO_TOKEN = adoToken;
|
|
1212
|
+
} catch { /* non-fatal */ }
|
|
1213
|
+
}
|
|
1196
1214
|
let resumeProc;
|
|
1197
1215
|
try {
|
|
1198
1216
|
resumeProc = runFile(process.execPath, [spawnScript, steerPromptPath, sysPromptPath, ...resumeArgs], {
|
|
@@ -1220,7 +1238,8 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1220
1238
|
startedAt: procInfo.startedAt,
|
|
1221
1239
|
runtimeName,
|
|
1222
1240
|
sessionId: steerSessionId,
|
|
1223
|
-
|
|
1241
|
+
_runtimeResumeAt: Date.now(),
|
|
1242
|
+
_runtimeResumeAwaitingFirstOutput: true,
|
|
1224
1243
|
_pendingSteeringFiles: mergePendingSteeringEntries(
|
|
1225
1244
|
procInfo._pendingSteeringFiles,
|
|
1226
1245
|
pendingForResume.entries,
|
|
@@ -1239,6 +1258,7 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1239
1258
|
if (stdout.length < MAX_OUTPUT) stdout += chunk.slice(0, MAX_OUTPUT - stdout.length);
|
|
1240
1259
|
try { fs.appendFileSync(liveOutputPath, chunk); } catch { /* optional */ }
|
|
1241
1260
|
const resumeInfo = activeProcesses.get(id);
|
|
1261
|
+
markRuntimeResumeOutputSeen(resumeInfo);
|
|
1242
1262
|
captureSessionIdFromStdoutChunk(agentId, id, branchName, runtime, resumeInfo, chunk, sessionCaptureState);
|
|
1243
1263
|
ackPendingSteeringFiles(agentId, resumeInfo, chunk);
|
|
1244
1264
|
});
|
|
@@ -1247,6 +1267,7 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1247
1267
|
realActivityMap.set(id, Date.now());
|
|
1248
1268
|
if (stderr.length < MAX_OUTPUT) stderr += chunk.slice(0, MAX_OUTPUT - stderr.length);
|
|
1249
1269
|
try { fs.appendFileSync(liveOutputPath, '[stderr] ' + chunk); } catch { /* optional */ }
|
|
1270
|
+
markRuntimeResumeOutputSeen(activeProcesses.get(id));
|
|
1250
1271
|
});
|
|
1251
1272
|
|
|
1252
1273
|
// Re-wire close handler for the resumed process
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1692",
|
|
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"
|
|
@@ -78,6 +78,38 @@ Concretely:
|
|
|
78
78
|
- If you skipped local validation, say so in the completion JSON (e.g. `tests: skipped — relying on PR pipeline`) and still exit.
|
|
79
79
|
- Holding a slot to watch a pipeline is wasted capacity; the engine has its own pipeline-monitoring path.
|
|
80
80
|
|
|
81
|
+
{{#github_shared_rules}}
|
|
82
|
+
## Checking PR and Build Status
|
|
83
|
+
|
|
84
|
+
When asked to check build status, CI results, or review state for a PR:
|
|
85
|
+
|
|
86
|
+
**Preferred — read cached state (refreshed every `prPollStatusEvery` ticks, default ~12 min when engine is running):**
|
|
87
|
+
Find the PR in `projects/<project-name>/pull-requests.json` by `prNumber`. Key fields:
|
|
88
|
+
- `buildStatus` — `passing` | `failing` | `running` | `none`
|
|
89
|
+
- `buildFailReason` — failing check/pipeline name when `buildStatus` is `failing`; inspect live CI logs yourself for details
|
|
90
|
+
- `reviewStatus` — `approved` | `changes-requested` | `waiting` | `pending`
|
|
91
|
+
- `status` — `active` | `merged` | `abandoned`
|
|
92
|
+
- `url` — link to the PR on GitHub
|
|
93
|
+
|
|
94
|
+
**Live status (when engine isn't running or you need up-to-the-moment results):**
|
|
95
|
+
```bash
|
|
96
|
+
gh pr view <prNumber> --json number,title,state,mergeable,reviewDecision,headRefName,baseRefName,statusCheckRollup --repo OWNER/REPO
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## GitHub Tooling and Auth
|
|
100
|
+
|
|
101
|
+
For GitHub repo operations, use GitHub MCP tools or the `gh` CLI. Prefer commands such as `gh pr create`, `gh pr view`, `gh pr comment`, `gh pr review --comment`, `gh issue view`, and `gh run view`.
|
|
102
|
+
|
|
103
|
+
If GitHub or Copilot auth fails, check GitHub/Copilot credentials only:
|
|
104
|
+
- `gh auth status`
|
|
105
|
+
- `gh auth login`
|
|
106
|
+
- `gh auth token` (for token visibility checks only; do not paste tokens into logs)
|
|
107
|
+
- Set `GH_TOKEN` or `COPILOT_GITHUB_TOKEN` only when the environment already provides an appropriate GitHub token.
|
|
108
|
+
|
|
109
|
+
Only GitHub/Copilot authentication guidance applies to GitHub repository work.
|
|
110
|
+
{{/github_shared_rules}}
|
|
111
|
+
|
|
112
|
+
{{#ado_shared_rules}}
|
|
81
113
|
## Checking PR and Build Status
|
|
82
114
|
|
|
83
115
|
When asked to check build status, CI results, or review state for a PR:
|
|
@@ -107,3 +139,4 @@ Output is JSON with the same fields. Exit 0 on success, 1 if not found.
|
|
|
107
139
|
For Azure DevOps repo operations, use the `az` CLI first. Prefer commands such as `az repos pr create`, `az repos pr show`, `az repos pr list`, `az repos pr comment`, `az repos pr reviewer`, `az boards work-item`, and `az pipelines` after setting defaults with `az devops configure`.
|
|
108
140
|
|
|
109
141
|
Use ADO MCP fallback tools (`mcp__azure-ado__*`) only when `az` is unavailable in the environment or insufficient for a specific operation. Do not choose MCP first just because it exists, and do not use `gh` for Azure DevOps repositories.
|
|
142
|
+
{{/ado_shared_rules}}
|