@algosuite/vo-mcp 0.2.0-beta.40 → 0.2.0-beta.42
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/dist/agent-auth-probe-cli.mjs +13 -2
- package/dist/cli.js +9 -2
- package/dist/cli.js.map +2 -2
- package/dist/runner-cli.js +108 -21
- package/dist/runner-cli.js.map +3 -3
- package/dist/runner-supervisor.js +13 -2
- package/dist/runner-supervisor.js.map +2 -2
- package/dist/set-key-cli.js +12 -4
- package/dist/set-key-cli.js.map +2 -2
- package/package.json +1 -1
package/dist/runner-cli.js
CHANGED
|
@@ -2416,7 +2416,7 @@ async function fetchInstallationToken({ req, required = false, readOnly = false,
|
|
|
2416
2416
|
const json = await res.json();
|
|
2417
2417
|
if (!json || !json.token) return fail("missing token");
|
|
2418
2418
|
if (readOnly && json.scope !== "read") return fail("control plane did not confirm a read-only grant");
|
|
2419
|
-
return { token: json.token, expiresAt: json.expires_at || null };
|
|
2419
|
+
return { token: json.token, expiresAt: json.expires_at || null, ...typeof json.ci_readable === "boolean" ? { ciReadable: json.ci_readable } : {} };
|
|
2420
2420
|
} catch (err) {
|
|
2421
2421
|
if (required) throw err;
|
|
2422
2422
|
return null;
|
|
@@ -2479,7 +2479,18 @@ async function resumeCodeTaskRequest(req, taskId, { automaticRateLimit = false,
|
|
|
2479
2479
|
onUnauthorized();
|
|
2480
2480
|
throw new Error("resume unauthorized (401)");
|
|
2481
2481
|
}
|
|
2482
|
-
if (!res.ok)
|
|
2482
|
+
if (!res.ok) {
|
|
2483
|
+
let code = null;
|
|
2484
|
+
try {
|
|
2485
|
+
const body = await res.json();
|
|
2486
|
+
code = typeof body?.error === "string" ? body.error : null;
|
|
2487
|
+
} catch {
|
|
2488
|
+
}
|
|
2489
|
+
const err = new Error(`resume failed: HTTP ${res.status}${code ? ` (${code})` : ""}`);
|
|
2490
|
+
err.status = res.status;
|
|
2491
|
+
err.code = code;
|
|
2492
|
+
throw err;
|
|
2493
|
+
}
|
|
2483
2494
|
const json = await res.json();
|
|
2484
2495
|
return json && json.task ? json.task : null;
|
|
2485
2496
|
}
|
|
@@ -3921,6 +3932,12 @@ var init_agent_token_usage = __esm({
|
|
|
3921
3932
|
});
|
|
3922
3933
|
|
|
3923
3934
|
// ../../scripts/virtual-office/code-runner/claude-result-event.mjs
|
|
3935
|
+
function cappedRunLastMessage(evt, lastProgress) {
|
|
3936
|
+
const summary = String(evt?.summary || "").trim();
|
|
3937
|
+
const salvage = String(lastProgress || "").trim();
|
|
3938
|
+
if (!salvage || !CAPPED_RESULT_SUBTYPES.includes(summary)) return null;
|
|
3939
|
+
return salvage;
|
|
3940
|
+
}
|
|
3924
3941
|
function buildResultEvent(evt) {
|
|
3925
3942
|
const isError = Boolean(evt.is_error) || evt.subtype === "error_max_turns" || evt.subtype === "error_during_execution";
|
|
3926
3943
|
return {
|
|
@@ -3933,10 +3950,12 @@ function buildResultEvent(evt) {
|
|
|
3933
3950
|
modelUsage: extractModelUsage(evt)
|
|
3934
3951
|
};
|
|
3935
3952
|
}
|
|
3953
|
+
var CAPPED_RESULT_SUBTYPES;
|
|
3936
3954
|
var init_claude_result_event = __esm({
|
|
3937
3955
|
"../../scripts/virtual-office/code-runner/claude-result-event.mjs"() {
|
|
3938
3956
|
"use strict";
|
|
3939
3957
|
init_agent_token_usage();
|
|
3958
|
+
CAPPED_RESULT_SUBTYPES = Object.freeze(["error_max_budget_usd", "error_max_turns"]);
|
|
3940
3959
|
}
|
|
3941
3960
|
});
|
|
3942
3961
|
|
|
@@ -4250,7 +4269,7 @@ function runAgentTask({
|
|
|
4250
4269
|
} catch {
|
|
4251
4270
|
}
|
|
4252
4271
|
let buffer = "";
|
|
4253
|
-
let result = { ok: false, costUsd: null, costBasis, summary: "", numTurns: null, tokenUsage: null, modelUsage: null, executionStarted: false, killed: false };
|
|
4272
|
+
let result = { ok: false, costUsd: null, costBasis, summary: "", lastAgentMessage: null, numTurns: null, tokenUsage: null, modelUsage: null, executionStarted: false, killed: false };
|
|
4254
4273
|
child.once("spawn", () => {
|
|
4255
4274
|
result = { ...result, executionStarted: true };
|
|
4256
4275
|
Promise.resolve(onSpawn()).catch(() => {
|
|
@@ -4285,6 +4304,9 @@ function runAgentTask({
|
|
|
4285
4304
|
costUsd: evt.costUsd,
|
|
4286
4305
|
costBasis: result.costBasis,
|
|
4287
4306
|
summary,
|
|
4307
|
+
// A budget/turn-capped run's honest last message, kept OUT of summary (see
|
|
4308
|
+
// claude-result-event.cappedRunLastMessage) and surfaced in the PR body.
|
|
4309
|
+
lastAgentMessage: cappedRunLastMessage(evt, lastProgress),
|
|
4288
4310
|
numTurns: evt.numTurns,
|
|
4289
4311
|
// MUST be listed explicitly. This assignment spreads the PREVIOUS
|
|
4290
4312
|
// result and then names each field it carries forward, so anything
|
|
@@ -4423,6 +4445,7 @@ var init_claude_runner = __esm({
|
|
|
4423
4445
|
init_orphan_agent_reaper();
|
|
4424
4446
|
init_agent_token_usage();
|
|
4425
4447
|
init_claude_stream_event();
|
|
4448
|
+
init_claude_result_event();
|
|
4426
4449
|
init_claude_auth_check();
|
|
4427
4450
|
ClaudeRunner = class {
|
|
4428
4451
|
get enforcesBudgetCap() {
|
|
@@ -4527,7 +4550,14 @@ var init_agent_key_store = __esm({
|
|
|
4527
4550
|
"oai-compat": ["VO_CODE_RUNNER_OAI_API_KEY"],
|
|
4528
4551
|
// Sovereign local inference (Ollama / LM Studio). The key is OPTIONAL — most
|
|
4529
4552
|
// local servers need none — and exists for locally secured endpoints only.
|
|
4530
|
-
local: ["VO_CODE_RUNNER_LOCAL_API_KEY"]
|
|
4553
|
+
local: ["VO_CODE_RUNNER_LOCAL_API_KEY"],
|
|
4554
|
+
// AlgoHQ cloud consensus (ADR-002 moat plane) entitlement token. Not a model
|
|
4555
|
+
// key: it authorises the runner's `vo_consensus_judgment` / `vo_verify_answer`
|
|
4556
|
+
// tools against the moat. On an npm-installed runner the local consensus
|
|
4557
|
+
// engine is never present (it is a workspace-only package), so WITHOUT this
|
|
4558
|
+
// token every consensus call answers `unimplemented /
|
|
4559
|
+
// consensus-engine-package-not-installed` (2026-08-16 finding, task fbd8659b).
|
|
4560
|
+
moat: ["VO_ENTITLEMENT_TOKEN"]
|
|
4531
4561
|
};
|
|
4532
4562
|
PROVIDER_ALIAS = {
|
|
4533
4563
|
claude: "anthropic",
|
|
@@ -4543,7 +4573,10 @@ var init_agent_key_store = __esm({
|
|
|
4543
4573
|
"oai-compat": "oai-compat",
|
|
4544
4574
|
local: "local",
|
|
4545
4575
|
ollama: "local",
|
|
4546
|
-
lmstudio: "local"
|
|
4576
|
+
lmstudio: "local",
|
|
4577
|
+
moat: "moat",
|
|
4578
|
+
entitlement: "moat",
|
|
4579
|
+
consensus: "moat"
|
|
4547
4580
|
};
|
|
4548
4581
|
_loadTried2 = false;
|
|
4549
4582
|
}
|
|
@@ -9051,6 +9084,9 @@ function ciFixOccurrenceKey({ repo, prNumber, headSha, repairAttempt }) {
|
|
|
9051
9084
|
function coordinationRetryDue(entry, nowMs) {
|
|
9052
9085
|
return !entry.nextRetryAt || nowMs >= entry.nextRetryAt;
|
|
9053
9086
|
}
|
|
9087
|
+
function isTerminalResumeRefusal(error) {
|
|
9088
|
+
return typeof error?.code === "string" && TERMINAL_RESUME_REFUSALS.includes(error.code);
|
|
9089
|
+
}
|
|
9054
9090
|
async function scheduleCoordinationRetry({
|
|
9055
9091
|
entry,
|
|
9056
9092
|
kind,
|
|
@@ -9061,6 +9097,14 @@ async function scheduleCoordinationRetry({
|
|
|
9061
9097
|
error,
|
|
9062
9098
|
log: log2
|
|
9063
9099
|
}) {
|
|
9100
|
+
if (kind === "resume" && isTerminalResumeRefusal(error)) {
|
|
9101
|
+
entry.needsContinuation = false;
|
|
9102
|
+
entry.continuationExhausted = true;
|
|
9103
|
+
entry.continuationRefusal = error.code;
|
|
9104
|
+
entry.continuationRefusedAt = now();
|
|
9105
|
+
log2(`watch: pr #${prNumber} automatic continuation refused by the plane (${error.code}); no retry \u2014 operator may resume explicitly with a larger cap`);
|
|
9106
|
+
return;
|
|
9107
|
+
}
|
|
9064
9108
|
const errorsKey = kind === "resume" ? "resumeErrors" : "enqueueErrors";
|
|
9065
9109
|
const attemptsKey = kind === "resume" ? "resumeAttempts" : "fixAttempts";
|
|
9066
9110
|
entry[errorsKey] = (entry[errorsKey] || 0) + 1;
|
|
@@ -9080,12 +9124,23 @@ async function scheduleCoordinationRetry({
|
|
|
9080
9124
|
}
|
|
9081
9125
|
log2(`watch: pr #${prNumber} ${kind} coordination failed ${entry[errorsKey]}x; retry in ${Math.round(delay2 / 1e3)}s: ${boundedErrorMessage(error)}`);
|
|
9082
9126
|
}
|
|
9083
|
-
var MAX_BACKOFF_MS;
|
|
9127
|
+
var MAX_BACKOFF_MS, TERMINAL_RESUME_REFUSALS;
|
|
9084
9128
|
var init_watcher_coordination = __esm({
|
|
9085
9129
|
"../../scripts/virtual-office/code-runner/watcher-coordination.mjs"() {
|
|
9086
9130
|
"use strict";
|
|
9087
9131
|
init_error_message();
|
|
9088
9132
|
MAX_BACKOFF_MS = 60 * 60 * 1e3;
|
|
9133
|
+
TERMINAL_RESUME_REFUSALS = Object.freeze([
|
|
9134
|
+
"automatic_continuation_budget_too_small",
|
|
9135
|
+
"automatic_continuation_budget_required",
|
|
9136
|
+
"continuation_spend_ceiling_reached",
|
|
9137
|
+
"continuation_budget_exhausted",
|
|
9138
|
+
"continuation_spend_unmeasured",
|
|
9139
|
+
"continuation_lineage_incomplete",
|
|
9140
|
+
"continuation_lineage_invalid",
|
|
9141
|
+
"cancelled_not_automatically_resumable",
|
|
9142
|
+
"not_resumable"
|
|
9143
|
+
]);
|
|
9089
9144
|
}
|
|
9090
9145
|
});
|
|
9091
9146
|
|
|
@@ -9201,7 +9256,7 @@ async function adoptPrOpenedTasks(tasks, {
|
|
|
9201
9256
|
if (operators.size > 0 && !operators.has(task.operator_id)) continue;
|
|
9202
9257
|
const key = watcherKey(state, task.repo, task.pr_number);
|
|
9203
9258
|
if (state[key]) continue;
|
|
9204
|
-
const partial = String(task.result || "").
|
|
9259
|
+
const partial = String(task.result || "").includes(PARTIAL_PR_CONTINUATION_MARKER);
|
|
9205
9260
|
const repairChain = task.repair_chain ?? {
|
|
9206
9261
|
root_pr_number: task.repair_pr_number ?? task.pr_number,
|
|
9207
9262
|
attempt: task.repair_pr_number ? 1 : 0,
|
|
@@ -9240,8 +9295,10 @@ var init_watcher_adoption = __esm({
|
|
|
9240
9295
|
});
|
|
9241
9296
|
|
|
9242
9297
|
// ../../scripts/virtual-office/code-runner/watcher-github-token.mjs
|
|
9243
|
-
function makeWatcherTokenProvider(client, { required = true, allowAmbient = false, now = () => Date.now()
|
|
9298
|
+
function makeWatcherTokenProvider(client, { required = true, allowAmbient = false, now = () => Date.now(), log: log2 = () => {
|
|
9299
|
+
} } = {}) {
|
|
9244
9300
|
const cache = /* @__PURE__ */ new Map();
|
|
9301
|
+
let ciUnreadableLoggedAt = null;
|
|
9245
9302
|
return async (repo) => {
|
|
9246
9303
|
const key = String(repo).toLowerCase();
|
|
9247
9304
|
const prior = cache.get(key);
|
|
@@ -9251,6 +9308,10 @@ function makeWatcherTokenProvider(client, { required = true, allowAmbient = fals
|
|
|
9251
9308
|
if (allowAmbient) return null;
|
|
9252
9309
|
throw new Error(`GitHub App read token unavailable for ${repo}`);
|
|
9253
9310
|
}
|
|
9311
|
+
if (result.ciReadable === false && (ciUnreadableLoggedAt === null || now() - ciUnreadableLoggedAt > 6 * 60 * 60 * 1e3)) {
|
|
9312
|
+
ciUnreadableLoggedAt = now();
|
|
9313
|
+
log2(`watch: the plane minted a read token for ${repo} WITHOUT CI read (ci_readable=false \u2014 the GitHub App installation has not accepted checks:read/statuses:read); PR CI stays unreadable until the operator accepts the App permission update`);
|
|
9314
|
+
}
|
|
9254
9315
|
cache.set(key, { token: result.token, at: now() });
|
|
9255
9316
|
return result.token;
|
|
9256
9317
|
};
|
|
@@ -9298,25 +9359,47 @@ var init_ci_fix_prompt = __esm({
|
|
|
9298
9359
|
});
|
|
9299
9360
|
|
|
9300
9361
|
// ../../scripts/virtual-office/code-runner/pr-watcher-github.mjs
|
|
9301
|
-
|
|
9302
|
-
const
|
|
9362
|
+
function isCiUnreadableError(err) {
|
|
9363
|
+
const text = `${err?.message || ""}
|
|
9364
|
+
${err?.stderr || ""}`;
|
|
9365
|
+
return /Resource not accessible by integration/i.test(text) && /statusCheckRollup/i.test(text);
|
|
9366
|
+
}
|
|
9367
|
+
function noteCiUnreadable(log2) {
|
|
9368
|
+
const now = Date.now();
|
|
9369
|
+
if (now - lastDiagnosticAt < DIAGNOSTIC_INTERVAL_MS) return;
|
|
9370
|
+
lastDiagnosticAt = now;
|
|
9371
|
+
log2("watch: CI status is UNREADABLE with the GitHub App read token (the installation has not granted checks:read/statuses:read \u2014 accept the App permission update on the installation). Auto-fix and merge stay dormant; untrack/resume keep working on state alone.");
|
|
9372
|
+
}
|
|
9373
|
+
async function ghViewPr(prNumber, repo, { githubToken, log: log2 = (m) => console.error(`[vo-runner] ${m}`), run = runProcess2 } = {}) {
|
|
9374
|
+
const env2 = githubToken ? { ...process.env, GH_TOKEN: githubToken } : process.env;
|
|
9375
|
+
const view = async (fields) => JSON.parse(await run("gh", [
|
|
9303
9376
|
"pr",
|
|
9304
9377
|
"view",
|
|
9305
9378
|
String(prNumber),
|
|
9306
9379
|
"-R",
|
|
9307
9380
|
repo,
|
|
9308
9381
|
"--json",
|
|
9309
|
-
|
|
9310
|
-
], {
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
})
|
|
9314
|
-
|
|
9382
|
+
fields
|
|
9383
|
+
], { timeout: 3e4, env: env2 }) || "{}");
|
|
9384
|
+
try {
|
|
9385
|
+
return await view(VIEW_FIELDS_WITH_CI);
|
|
9386
|
+
} catch (err) {
|
|
9387
|
+
if (!isCiUnreadableError(err)) throw err;
|
|
9388
|
+
noteCiUnreadable(log2);
|
|
9389
|
+
const withoutCi = await view(VIEW_FIELDS_WITHOUT_CI);
|
|
9390
|
+
return { ...withoutCi, statusCheckRollup: null, ciUnreadable: true, ciUnreadableReason: CI_UNREADABLE_REASON };
|
|
9391
|
+
}
|
|
9315
9392
|
}
|
|
9393
|
+
var VIEW_FIELDS_WITH_CI, VIEW_FIELDS_WITHOUT_CI, CI_UNREADABLE_REASON, DIAGNOSTIC_INTERVAL_MS, lastDiagnosticAt;
|
|
9316
9394
|
var init_pr_watcher_github = __esm({
|
|
9317
9395
|
"../../scripts/virtual-office/code-runner/pr-watcher-github.mjs"() {
|
|
9318
9396
|
"use strict";
|
|
9319
9397
|
init_process_runner2();
|
|
9398
|
+
VIEW_FIELDS_WITH_CI = "state,statusCheckRollup,headRefName,headRefOid,url,isDraft,mergeStateStatus";
|
|
9399
|
+
VIEW_FIELDS_WITHOUT_CI = "state,headRefName,headRefOid,url,isDraft,mergeStateStatus";
|
|
9400
|
+
CI_UNREADABLE_REASON = "app_token_missing_checks_read";
|
|
9401
|
+
DIAGNOSTIC_INTERVAL_MS = 30 * 60 * 1e3;
|
|
9402
|
+
lastDiagnosticAt = 0;
|
|
9320
9403
|
}
|
|
9321
9404
|
});
|
|
9322
9405
|
|
|
@@ -9377,7 +9460,7 @@ function parsePrCiStatus(view) {
|
|
|
9377
9460
|
else if (st !== "SUCCESS") pending = true;
|
|
9378
9461
|
}
|
|
9379
9462
|
}
|
|
9380
|
-
const ci = failedChecks.length > 0 ? "failing" : pending ? "pending" : "passing";
|
|
9463
|
+
const ci = view?.ciUnreadable ? "unknown" : failedChecks.length > 0 ? "failing" : pending ? "pending" : "passing";
|
|
9381
9464
|
return {
|
|
9382
9465
|
state,
|
|
9383
9466
|
ci,
|
|
@@ -9576,7 +9659,7 @@ async function runWatchCycleUnlocked({
|
|
|
9576
9659
|
try {
|
|
9577
9660
|
if (typeof reportBlocker === "function") await reportBlocker({
|
|
9578
9661
|
taskId: entry.taskId,
|
|
9579
|
-
message: entry.continuationExhausted ? `PR #${prNumber} remains a partial draft after its bounded automatic continuation; watcher is still monitoring and operator review is required before more spend.` : `PR #${prNumber} remains failing after ${entry.fixAttempts || 0} bounded repair attempt(s); watcher is still monitoring and operator review is required.`
|
|
9662
|
+
message: entry.continuationExhausted ? `PR #${prNumber} remains a partial draft after its bounded automatic continuation${entry.continuationRefusal ? ` (plane refused: ${entry.continuationRefusal})` : ""}; watcher is still monitoring and operator review is required before more spend.` : `PR #${prNumber} remains failing after ${entry.fixAttempts || 0} bounded repair attempt(s); watcher is still monitoring and operator review is required.`
|
|
9580
9663
|
});
|
|
9581
9664
|
entry.escalatedAt = now();
|
|
9582
9665
|
escalated += 1;
|
|
@@ -9611,9 +9694,10 @@ function makeWatchRunner({
|
|
|
9611
9694
|
}) {
|
|
9612
9695
|
const tokenForRepo = makeWatcherTokenProvider(client, {
|
|
9613
9696
|
required: !allowAmbientGithub,
|
|
9614
|
-
allowAmbient: allowAmbientGithub
|
|
9697
|
+
allowAmbient: allowAmbientGithub,
|
|
9698
|
+
log: log2
|
|
9615
9699
|
});
|
|
9616
|
-
const watchView = viewPr === ghViewPr ? async (prNumber, repo) => ghViewPr(prNumber, repo, { githubToken: await tokenForRepo(repo) }) : viewPr;
|
|
9700
|
+
const watchView = viewPr === ghViewPr ? async (prNumber, repo) => ghViewPr(prNumber, repo, { githubToken: await tokenForRepo(repo), log: log2 }) : viewPr;
|
|
9617
9701
|
return async () => {
|
|
9618
9702
|
const openTasks = typeof client.listPrOpenedTasks === "function" ? await client.listPrOpenedTasks() : [];
|
|
9619
9703
|
const adopted = await adoptPrOpenedTasks(openTasks, {
|
|
@@ -11526,6 +11610,9 @@ function buildPrBody(task, run, files, { armAutoMerge = false } = {}) {
|
|
|
11526
11610
|
"",
|
|
11527
11611
|
redactSecrets(String(run.summary || "")).slice(0, 2e3),
|
|
11528
11612
|
"",
|
|
11613
|
+
// A budget/turn-capped run ends with no assistant text (summary = the bare
|
|
11614
|
+
// subtype); its LAST message is the honest report the operator needs.
|
|
11615
|
+
...run.lastAgentMessage ? ["### Last agent message before the cap", "", redactSecrets(String(run.lastAgentMessage)).slice(0, 2e3), ""] : [],
|
|
11529
11616
|
"---",
|
|
11530
11617
|
armAutoMerge ? "_Opened by the AlgoHQ code-runner daemon. After CI passes, the watcher must obtain a durable consensus receipt and merge the exact verified SHA._" : "_Opened by the AlgoHQ code-runner daemon. This PR awaits the verify-before-act gate / operator review \u2014 it is NOT auto-merged._"
|
|
11531
11618
|
].filter((l) => l !== "").join("\n");
|
|
@@ -13101,7 +13188,7 @@ function reportsBlocker(summary) {
|
|
|
13101
13188
|
return /\btask remains\s+(?:\*\*)?BLOCKED\b/i.test(text) || /(?:^|\n)\s*(?:#{1,6}\s*)?(?:\*\*)?(?:host-recovery\s+)?(?:result|outcome|status)\s*:\s*(?:\*\*)?BLOCKED\b/im.test(text);
|
|
13102
13189
|
}
|
|
13103
13190
|
function isMaxTurnExhaustion(run = {}, maxTurns) {
|
|
13104
|
-
const summary = String(run.summary || "").trim().toLowerCase();
|
|
13191
|
+
const summary = String(run.summary || "").trim().toLowerCase().split("\n")[0].trim();
|
|
13105
13192
|
if (summary === "error_max_turns" || summary === "inconclusive_max_turns") return true;
|
|
13106
13193
|
return Number.isInteger(maxTurns) && maxTurns > 0 && Number.isInteger(run.numTurns) && run.numTurns > maxTurns;
|
|
13107
13194
|
}
|