@algosuite/vo-mcp 0.2.0-beta.38 → 0.2.0-beta.39
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 +10 -5
- package/dist/cli.js +58 -0
- package/dist/cli.js.map +2 -2
- package/dist/index.js +56 -0
- package/dist/index.js.map +2 -2
- package/dist/runner-cli.js +181 -30
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +36 -0
- package/dist/runner-supervisor.js.map +3 -3
- package/package.json +1 -1
package/dist/runner-cli.js
CHANGED
|
@@ -2566,6 +2566,44 @@ var init_control_plane_merge = __esm({
|
|
|
2566
2566
|
}
|
|
2567
2567
|
});
|
|
2568
2568
|
|
|
2569
|
+
// ../../scripts/virtual-office/code-runner/claim-gate-notice.mjs
|
|
2570
|
+
function describeClaimGate(gate) {
|
|
2571
|
+
if (!gate || gate.allowed !== false) return null;
|
|
2572
|
+
const reason = String(gate.reason || "denied");
|
|
2573
|
+
const floor = gate.floor_version ? ` (floor ${gate.floor_version})` : "";
|
|
2574
|
+
return `claim gate: DENIED \u2014 ${reason}${floor}: ${(Object.hasOwn(REASON_HELP, reason) ? REASON_HELP[reason] : null) ?? "the control plane refused this runner's claims"}`;
|
|
2575
|
+
}
|
|
2576
|
+
function makeClaimGateNotice({ log: log2 = () => {
|
|
2577
|
+
} } = {}) {
|
|
2578
|
+
let last = null;
|
|
2579
|
+
let current = null;
|
|
2580
|
+
return {
|
|
2581
|
+
current: () => current,
|
|
2582
|
+
observe(json) {
|
|
2583
|
+
const gate = json && typeof json === "object" ? json.claim_gate : null;
|
|
2584
|
+
const denied = gate && gate.allowed === false ? gate : null;
|
|
2585
|
+
current = denied ? { ...denied, observed_at: (/* @__PURE__ */ new Date()).toISOString() } : null;
|
|
2586
|
+
const signature = denied ? `${denied.reason}|${denied.floor_version ?? ""}` : null;
|
|
2587
|
+
if (signature === last) return;
|
|
2588
|
+
if (denied) log2(describeClaimGate(denied));
|
|
2589
|
+
else if (last !== null) log2("claim gate: allowed again \u2014 this runner may claim work");
|
|
2590
|
+
last = signature;
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
var REASON_HELP;
|
|
2595
|
+
var init_claim_gate_notice = __esm({
|
|
2596
|
+
"../../scripts/virtual-office/code-runner/claim-gate-notice.mjs"() {
|
|
2597
|
+
"use strict";
|
|
2598
|
+
REASON_HELP = {
|
|
2599
|
+
daemon_version_below_floor: "this daemon is older than the approved release target \u2014 it idles until the governed updater brings it current (operator override: VO_RUNNER_CLAIM_MIN_DAEMON_VERSION / VO_RUNNER_CLAIM_VERSION_GATE=off on the control plane)",
|
|
2600
|
+
daemon_version_unreported: "this daemon reports no parseable version in its heartbeat \u2014 too old for the updater to manage, so it may not claim work",
|
|
2601
|
+
no_fresh_heartbeat: "the control plane has no fresh heartbeat from this runner \u2014 claims resume once heartbeats land",
|
|
2602
|
+
runner_denylisted: "this runner id is on the operator quarantine list (VO_RUNNER_CLAIM_DENYLIST)"
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
});
|
|
2606
|
+
|
|
2569
2607
|
// src/runner/control-plane-auth-stub.mjs
|
|
2570
2608
|
var control_plane_auth_stub_exports = {};
|
|
2571
2609
|
__export(control_plane_auth_stub_exports, {
|
|
@@ -2641,7 +2679,10 @@ function createControlPlaneClient({
|
|
|
2641
2679
|
}
|
|
2642
2680
|
}
|
|
2643
2681
|
const taskReq = (method, path22, body, options = {}) => req(method, path22, body, { timeoutMs: taskRequestTimeoutMs, ...options });
|
|
2682
|
+
const claimGate = makeClaimGateNotice({ log: (m) => console.warn(`[code-runner ${(/* @__PURE__ */ new Date()).toISOString()}] ${m}`) });
|
|
2644
2683
|
return {
|
|
2684
|
+
getClaimGate: () => claimGate.current(),
|
|
2685
|
+
// last DENIED claim-gate verdict (null when allowed) — for /status + tests
|
|
2645
2686
|
...makeAutonomousDispatchAdmissionClient(
|
|
2646
2687
|
req,
|
|
2647
2688
|
taskRequestTimeoutMs,
|
|
@@ -2676,6 +2717,7 @@ function createControlPlaneClient({
|
|
|
2676
2717
|
}
|
|
2677
2718
|
if (!res.ok) throw new Error(`claim failed: HTTP ${res.status}`);
|
|
2678
2719
|
const json = await res.json();
|
|
2720
|
+
claimGate.observe(json);
|
|
2679
2721
|
return json && json.task ? json.task : null;
|
|
2680
2722
|
},
|
|
2681
2723
|
/**
|
|
@@ -2946,6 +2988,7 @@ var init_control_plane_client = __esm({
|
|
|
2946
2988
|
init_control_plane_resume();
|
|
2947
2989
|
init_control_plane_autonomous_admission();
|
|
2948
2990
|
init_control_plane_merge();
|
|
2991
|
+
init_claim_gate_notice();
|
|
2949
2992
|
cachedFirebaseToken = null;
|
|
2950
2993
|
ClaimAuthorityChangedError = class extends Error {
|
|
2951
2994
|
constructor() {
|
|
@@ -3445,11 +3488,14 @@ function normalizeClaudePermissionMode(value) {
|
|
|
3445
3488
|
}
|
|
3446
3489
|
return normalized;
|
|
3447
3490
|
}
|
|
3448
|
-
function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, model, effort, maxBudgetUsd, env: env2 = process.env } = {}) {
|
|
3491
|
+
function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, model, effort, maxBudgetUsd, researchHarness = false, env: env2 = process.env } = {}) {
|
|
3449
3492
|
const effectivePermissionMode = normalizeClaudePermissionMode(permissionMode);
|
|
3450
|
-
const
|
|
3493
|
+
const noWeb = String(env2?.VO_CODE_RUNNER_NO_WEB ?? "").trim() === "1";
|
|
3494
|
+
const research = noWeb ? [] : VO_RESEARCH_TOOLS;
|
|
3495
|
+
const noWorkflow = noWeb || String(env2?.VO_CODE_RUNNER_NO_WORKFLOW ?? "").trim() === "1";
|
|
3496
|
+
const workflow = researchHarness === true && !noWorkflow ? VO_WORKFLOW_TOOLS : [];
|
|
3451
3497
|
const baseTools = effectivePermissionMode === DEFAULT_PERMISSION_MODE ? [VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL] : [VO_SESSION_STATE_TOOL];
|
|
3452
|
-
const allowedTools = [...baseTools, ...research].join(",");
|
|
3498
|
+
const allowedTools = [...baseTools, ...research, ...workflow].join(",");
|
|
3453
3499
|
const args = [
|
|
3454
3500
|
"-p",
|
|
3455
3501
|
"--output-format",
|
|
@@ -3475,7 +3521,7 @@ function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, m
|
|
|
3475
3521
|
args.push(...context7McpArgs(env2));
|
|
3476
3522
|
return args;
|
|
3477
3523
|
}
|
|
3478
|
-
var DEFAULT_PERMISSION_MODE, VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL, VO_RESEARCH_TOOLS, SAFE_PERMISSION_MODES;
|
|
3524
|
+
var DEFAULT_PERMISSION_MODE, VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL, VO_RESEARCH_TOOLS, VO_WORKFLOW_TOOLS, SAFE_PERMISSION_MODES;
|
|
3479
3525
|
var init_claude_args = __esm({
|
|
3480
3526
|
"../../scripts/virtual-office/code-runner/claude-args.mjs"() {
|
|
3481
3527
|
"use strict";
|
|
@@ -3485,6 +3531,7 @@ var init_claude_args = __esm({
|
|
|
3485
3531
|
VO_HEADLESS_PNPM_TOOL = "Bash(pnpm *)";
|
|
3486
3532
|
VO_HEADLESS_PNPM_FROM_DIR_TOOL = "Bash(pnpm --dir *)";
|
|
3487
3533
|
VO_RESEARCH_TOOLS = ["WebFetch", "WebSearch"];
|
|
3534
|
+
VO_WORKFLOW_TOOLS = ["Workflow"];
|
|
3488
3535
|
SAFE_PERMISSION_MODES = /* @__PURE__ */ new Set(["acceptEdits", "plan", "default", "dontAsk", "delegate"]);
|
|
3489
3536
|
}
|
|
3490
3537
|
});
|
|
@@ -3857,14 +3904,15 @@ function runOutcomePatch(run) {
|
|
|
3857
3904
|
if (run?.executionStarted === true) patch.execution_started = true;
|
|
3858
3905
|
return { ...patch, ...tokenUsagePatch(run) };
|
|
3859
3906
|
}
|
|
3860
|
-
var MAX_TOKEN_COUNT, MAX_COST_USD, MAX_TURNS, COST_BASES, MAX_MODELS;
|
|
3907
|
+
var MAX_TOKEN_COUNT, MAX_COST_USD, MAX_TURNS, COST_BASES, NO_AGENT_SPAWNED_ECONOMICS, MAX_MODELS;
|
|
3861
3908
|
var init_agent_token_usage = __esm({
|
|
3862
3909
|
"../../scripts/virtual-office/code-runner/agent-token-usage.mjs"() {
|
|
3863
3910
|
"use strict";
|
|
3864
3911
|
MAX_TOKEN_COUNT = 1e9;
|
|
3865
3912
|
MAX_COST_USD = 1e4;
|
|
3866
3913
|
MAX_TURNS = 1e4;
|
|
3867
|
-
COST_BASES = /* @__PURE__ */ new Set(["vendor_billed", "subscription_api_equivalent", "local_zero", "unknown"]);
|
|
3914
|
+
COST_BASES = /* @__PURE__ */ new Set(["vendor_billed", "subscription_api_equivalent", "local_zero", "unknown", "no_agent_spawned"]);
|
|
3915
|
+
NO_AGENT_SPAWNED_ECONOMICS = Object.freeze({ cost_usd: 0, cost_basis: "no_agent_spawned" });
|
|
3868
3916
|
MAX_MODELS = 20;
|
|
3869
3917
|
}
|
|
3870
3918
|
});
|
|
@@ -4136,6 +4184,7 @@ function runAgentTask({
|
|
|
4136
4184
|
model,
|
|
4137
4185
|
effort = null,
|
|
4138
4186
|
maxBudgetUsd = null,
|
|
4187
|
+
researchHarness = false,
|
|
4139
4188
|
env: env2 = process.env,
|
|
4140
4189
|
onProgress = () => {
|
|
4141
4190
|
},
|
|
@@ -4153,7 +4202,7 @@ function runAgentTask({
|
|
|
4153
4202
|
sandbox = null
|
|
4154
4203
|
}) {
|
|
4155
4204
|
return new Promise((resolve2) => {
|
|
4156
|
-
const args = runner.buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, prompt });
|
|
4205
|
+
const args = runner.buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness, prompt });
|
|
4157
4206
|
const spawnEnv = typeof runner.applyAuthEnv === "function" ? runner.applyAuthEnv(env2) : env2;
|
|
4158
4207
|
const costBasis = typeof runner.costBasis === "function" ? runner.costBasis(spawnEnv) : "unknown";
|
|
4159
4208
|
if (costBasis === "vendor_billed" && runner.enforcesBudgetCap !== true && env2.VO_CODE_RUNNER_ALLOW_UNCAPPED_VENDOR_BILLED !== "1") {
|
|
@@ -4379,8 +4428,8 @@ var init_claude_runner = __esm({
|
|
|
4379
4428
|
get binary() {
|
|
4380
4429
|
return "claude";
|
|
4381
4430
|
}
|
|
4382
|
-
buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd } = {}) {
|
|
4383
|
-
return buildClaudeArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd });
|
|
4431
|
+
buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness } = {}) {
|
|
4432
|
+
return buildClaudeArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness });
|
|
4384
4433
|
}
|
|
4385
4434
|
parseEvent(line) {
|
|
4386
4435
|
return parseStreamEvent(line);
|
|
@@ -7189,12 +7238,12 @@ function composeMethodologyBlock(task) {
|
|
|
7189
7238
|
return { shape, stakes, block: lines.join("\n") };
|
|
7190
7239
|
}
|
|
7191
7240
|
function withMethodology(prompt, task) {
|
|
7192
|
-
const { shape, block } = composeMethodologyBlock(task);
|
|
7193
|
-
return { shape, prompt: `${prompt ?? ""}
|
|
7241
|
+
const { shape, stakes, block } = composeMethodologyBlock(task);
|
|
7242
|
+
return { shape, stakes, prompt: `${prompt ?? ""}
|
|
7194
7243
|
|
|
7195
7244
|
${block}` };
|
|
7196
7245
|
}
|
|
7197
|
-
var SHAPE_RULES, GOVERNED_STAKES_PATTERN, CONSENSUS_DIRECTIVES, UNIVERSAL_DIRECTIVES, SHAPE_DIRECTIVES;
|
|
7246
|
+
var SHAPE_RULES, GOVERNED_STAKES_PATTERN, RESEARCH_WORKFLOW_DIRECTIVE, CONSENSUS_DIRECTIVES, UNIVERSAL_DIRECTIVES, SHAPE_DIRECTIVES;
|
|
7198
7247
|
var init_methodology_composer = __esm({
|
|
7199
7248
|
"../../scripts/virtual-office/code-runner/methodology-composer.mjs"() {
|
|
7200
7249
|
"use strict";
|
|
@@ -7229,15 +7278,16 @@ var init_methodology_composer = __esm({
|
|
|
7229
7278
|
}
|
|
7230
7279
|
];
|
|
7231
7280
|
GOVERNED_STAKES_PATTERN = /\b(FERPA|IDOR|HIPAA|PII|privacy|security|authz|authorization|access[- ]control|permission[- ]denied|IRS|tax|§\s?\d|payroll|1099|W-2|MACRS|depreciation|billing|payment|refund|ledger|journal entr|reconcil|compliance|IEP\b|§?504\b|safeguard|governed fact)\b/iu;
|
|
7281
|
+
RESEARCH_WORKFLOW_DIRECTIVE = "For a genuinely open research question (not a single-file or single-log lookup \u2014 those need no harness), use the office research harness rather than ad-hoc browsing: for an open-web question run the workflow at ~/.claude/workflows/storm-deep-research-budget.mjs (Workflow tool, scriptPath, the question as args); for a question about THIS repo run ~/.claude/workflows/deep-research-internal-budget.mjs. Use ONLY the -budget variants (sonnet investigators, one opus synthesis) and stay inside this task budget. If the Workflow tool or those scripts are unavailable on this host, say so in the report and run the same four stages yourself \u2014 perspectives, WebSearch/WebFetch investigation, an adversarial pass that tries to REFUTE each key claim, then a cited write-up \u2014 with at most cheap-tier subagents; never a Fable/Opus fan-out.";
|
|
7232
7282
|
CONSENSUS_DIRECTIVES = [
|
|
7233
|
-
"This task touches governed or high-stakes facts. BEFORE building tests around your central domain claim, run a multi-model consensus check on that claim (vo-mcp: vo_consensus_judgment or vo_verify_answer) and paste the verdict
|
|
7283
|
+
"This task touches governed or high-stakes facts. BEFORE building tests around your central domain claim, run a multi-model consensus check on that claim (vo-mcp: vo_consensus_judgment or vo_verify_answer) and paste the verdict AND the tool result's receipt_id (a UUID; present when the cloud moat verified) into the PR body as `receipt id: <uuid>` \u2014 never invent one, and if the result has no receipt_id say so. A wrong governed fact caught at the claim stage costs one panel call; caught at the PR stage it costs the whole task; caught in production it costs a user.",
|
|
7234
7284
|
"If the consensus tools are not available in this session, say exactly that in the PR body instead of silently skipping \u2014 an unverified governed claim must be visible, never implied."
|
|
7235
7285
|
];
|
|
7236
7286
|
UNIVERSAL_DIRECTIVES = [
|
|
7237
7287
|
"Verification is a stage, not a vibe: before publishing, run the tests/build your change touches and cite their actual output. A claim without execution evidence is not done.",
|
|
7238
7288
|
"Work to completion or end with an explicit failure reason. Do not stop because time has passed; stop when the evidence says the work is done \u2014 or state exactly what is blocking.",
|
|
7239
7289
|
"Default to doing the work yourself in this session. Spawn parallel subagents ONLY for pieces that are genuinely independent and independently verifiable \u2014 and verify their results yourself before integrating; never let unreviewed parallel output merge into shared files.",
|
|
7240
|
-
'If you must stop for an operator decision, NEVER post a bare "blocked \u2014 needs your call". Post the decision as 2-4 concrete lettered options, each one line with its tradeoff, name the recommended default, and state what you will safely do (or leave untouched) if no answer arrives. An escalation the operator cannot answer with one word is an unfinished escalation.'
|
|
7290
|
+
'If you must stop for an operator decision, NEVER post a bare "blocked \u2014 needs your call". Post the decision as 2-4 concrete lettered options, each one line with its tradeoff, name the recommended default, and state what you will safely do (or leave untouched) if no answer arrives. An escalation the operator cannot answer with one word is an unfinished escalation. ALSO emit the same decision as a fenced code block whose info string is vo-decision-request, containing ONE JSON object with keys question, options (2-4 items, each {key A-D, label, tradeoff}), recommended_key and safe_default \u2014 real text in every field (a placeholder like "..." is dropped), so Command Center can render one-click buttons.'
|
|
7241
7291
|
];
|
|
7242
7292
|
SHAPE_DIRECTIVES = {
|
|
7243
7293
|
"bug-fix": [
|
|
@@ -7245,7 +7295,8 @@ var init_methodology_composer = __esm({
|
|
|
7245
7295
|
],
|
|
7246
7296
|
research: [
|
|
7247
7297
|
"Every claim needs its source AND exact attribution \u2014 which file:line, which benchmark, which baseline, which version. Verify attribution, not just that a source exists; misattributed real facts are the dominant research failure mode.",
|
|
7248
|
-
"Deliver findings as a repo artifact (docs/) with the evidence inline, not only as chat output."
|
|
7298
|
+
"Deliver findings as a repo artifact (docs/) with the evidence inline, not only as chat output.",
|
|
7299
|
+
RESEARCH_WORKFLOW_DIRECTIVE
|
|
7249
7300
|
],
|
|
7250
7301
|
"roadmap-advance": [
|
|
7251
7302
|
"Update the roadmap doc status, regenerate the roadmap board if the doc changed, and add the roadmap-log fragment IN THIS SAME PR \u2014 a roadmap task that does not move the roadmap did not happen.",
|
|
@@ -7313,16 +7364,25 @@ function withAttachmentManifest(prompt, markdown) {
|
|
|
7313
7364
|
|
|
7314
7365
|
${manifest}` : prompt;
|
|
7315
7366
|
}
|
|
7316
|
-
function withComposedMethodology(prompt, task, log2, taskId) {
|
|
7317
|
-
const { shape, prompt: composed } = withMethodology(prompt, task);
|
|
7318
|
-
log2(`task ${taskId || "unknown-task"}: methodology shape=${shape}`);
|
|
7367
|
+
function withComposedMethodology(prompt, task, log2, taskId, onMethodology) {
|
|
7368
|
+
const { shape, stakes, prompt: composed } = withMethodology(prompt, task);
|
|
7369
|
+
log2(`task ${taskId || "unknown-task"}: methodology shape=${shape}${stakes ? ` governed-stakes=${stakes}` : ""}`);
|
|
7370
|
+
try {
|
|
7371
|
+
onMethodology?.({ shape, stakes: stakes ?? null });
|
|
7372
|
+
} catch {
|
|
7373
|
+
}
|
|
7319
7374
|
return composed;
|
|
7320
7375
|
}
|
|
7376
|
+
function methodologyLedgerFields(methodology) {
|
|
7377
|
+
const shape = String(methodology?.shape ?? "").trim().slice(0, 40);
|
|
7378
|
+
const stakes = String(methodology?.stakes ?? "").trim().slice(0, 60);
|
|
7379
|
+
return { ...shape ? { methodology_shape: shape } : {}, ...stakes ? { governed_stakes: stakes } : {} };
|
|
7380
|
+
}
|
|
7321
7381
|
async function composeCodeTaskPrompt(client, task, { log: log2 = () => {
|
|
7322
|
-
}, allowMissingKnowledgeContext = false, attachmentManifestMarkdown = "" } = {}) {
|
|
7382
|
+
}, allowMissingKnowledgeContext = false, attachmentManifestMarkdown = "", onMethodology } = {}) {
|
|
7323
7383
|
const taskId = task?.code_task_id;
|
|
7324
7384
|
if (!taskId) {
|
|
7325
|
-
return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(task?.prompt, attachmentManifestMarkdown), task, log2, taskId), {
|
|
7385
|
+
return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(task?.prompt, attachmentManifestMarkdown), task, log2, taskId, onMethodology), {
|
|
7326
7386
|
repo: task?.repo,
|
|
7327
7387
|
knowledgeContextMarkdown: handleMissingKnowledgeContext(taskId, "missing code_task_id on the claimed task", {
|
|
7328
7388
|
allowMissingKnowledgeContext,
|
|
@@ -7331,7 +7391,7 @@ async function composeCodeTaskPrompt(client, task, { log: log2 = () => {
|
|
|
7331
7391
|
});
|
|
7332
7392
|
}
|
|
7333
7393
|
if (typeof client?.getTaskKnowledgeContext !== "function") {
|
|
7334
|
-
return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(task?.prompt, attachmentManifestMarkdown), task, log2, taskId), {
|
|
7394
|
+
return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(task?.prompt, attachmentManifestMarkdown), task, log2, taskId, onMethodology), {
|
|
7335
7395
|
repo: task?.repo,
|
|
7336
7396
|
knowledgeContextMarkdown: handleMissingKnowledgeContext(taskId, "control-plane client cannot fetch knowledge context", {
|
|
7337
7397
|
allowMissingKnowledgeContext,
|
|
@@ -7360,7 +7420,7 @@ async function composeCodeTaskPrompt(client, task, { log: log2 = () => {
|
|
|
7360
7420
|
const prompt = operatorInstructions ? `${task?.prompt ?? ""}
|
|
7361
7421
|
|
|
7362
7422
|
${operatorInstructions}` : task?.prompt;
|
|
7363
|
-
return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(prompt, attachmentManifestMarkdown), task, log2, taskId), {
|
|
7423
|
+
return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(prompt, attachmentManifestMarkdown), task, log2, taskId, onMethodology), {
|
|
7364
7424
|
repo: task?.repo,
|
|
7365
7425
|
knowledgeContextMarkdown
|
|
7366
7426
|
});
|
|
@@ -9885,7 +9945,7 @@ function startControlServer({ port, getStatus, requestStop, allowedOrigin, log:
|
|
|
9885
9945
|
return server;
|
|
9886
9946
|
}
|
|
9887
9947
|
function startDaemonControl({ cfg, runnerInstanceId, requestStop, getActiveCount, isRunning, startedAt, log: log2 = () => {
|
|
9888
|
-
}, onDuplicate = null, getUpdateStatus = () => null }) {
|
|
9948
|
+
}, onDuplicate = null, getUpdateStatus = () => null, getClaimGate = () => null }) {
|
|
9889
9949
|
if (!cfg.controlEnabled) return null;
|
|
9890
9950
|
return startControlServer({
|
|
9891
9951
|
port: cfg.controlPort,
|
|
@@ -9904,7 +9964,10 @@ function startDaemonControl({ cfg, runnerInstanceId, requestStop, getActiveCount
|
|
|
9904
9964
|
startedAt: new Date(startedAt).toISOString(),
|
|
9905
9965
|
uptimeSec: Math.round((Date.now() - startedAt) / 1e3),
|
|
9906
9966
|
// Host version awareness — the app + `runner --status` read drift from here.
|
|
9907
|
-
updateStatus: getUpdateStatus()
|
|
9967
|
+
updateStatus: getUpdateStatus(),
|
|
9968
|
+
// Last claim-gate verdict from the control plane (null = allowed / never denied):
|
|
9969
|
+
// a below-floor runner idles on a benign empty queue; this is where the host says why.
|
|
9970
|
+
claimGate: getClaimGate()
|
|
9908
9971
|
}),
|
|
9909
9972
|
log: log2
|
|
9910
9973
|
});
|
|
@@ -12248,6 +12311,78 @@ var init_isolation_audit = __esm({
|
|
|
12248
12311
|
}
|
|
12249
12312
|
});
|
|
12250
12313
|
|
|
12314
|
+
// ../../scripts/virtual-office/code-runner/terminal-ledger-patch.mjs
|
|
12315
|
+
function clip(value, max) {
|
|
12316
|
+
if (typeof value !== "string") return "";
|
|
12317
|
+
const text = value.trim();
|
|
12318
|
+
if (text.length === 0 || PLACEHOLDER_RE.test(text)) return "";
|
|
12319
|
+
return text.slice(0, max);
|
|
12320
|
+
}
|
|
12321
|
+
function parseDecisionRequest(text) {
|
|
12322
|
+
const source = String(text ?? "");
|
|
12323
|
+
let match = null;
|
|
12324
|
+
for (const candidate of source.matchAll(new RegExp(FENCE_RE.source, "giu"))) match = candidate;
|
|
12325
|
+
if (!match) return null;
|
|
12326
|
+
let raw;
|
|
12327
|
+
try {
|
|
12328
|
+
raw = JSON.parse(match[1]);
|
|
12329
|
+
} catch {
|
|
12330
|
+
return null;
|
|
12331
|
+
}
|
|
12332
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
12333
|
+
const question = clip(raw.question, 1e3);
|
|
12334
|
+
const safeDefault = clip(raw.safe_default ?? raw.safeDefault, 500);
|
|
12335
|
+
const options = Array.isArray(raw.options) ? raw.options : [];
|
|
12336
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12337
|
+
const cleaned = [];
|
|
12338
|
+
for (const option of options) {
|
|
12339
|
+
if (!option || typeof option !== "object") return null;
|
|
12340
|
+
const key = typeof option.key === "string" ? option.key.trim().replace(/[).:\-\s]+$/u, "").toUpperCase() : "";
|
|
12341
|
+
const label = clip(option.label, 200);
|
|
12342
|
+
const tradeoff = clip(option.tradeoff, 300);
|
|
12343
|
+
if (!KEY_RE.test(key) || !label || !tradeoff || seen.has(key)) return null;
|
|
12344
|
+
seen.add(key);
|
|
12345
|
+
cleaned.push({ key, label, tradeoff });
|
|
12346
|
+
}
|
|
12347
|
+
const recommendedRaw = raw.recommended_key ?? raw.recommendedKey ?? raw.recommended;
|
|
12348
|
+
const recommended = typeof recommendedRaw === "string" ? recommendedRaw.trim().replace(/[).:\-\s]+$/u, "").toUpperCase() : "";
|
|
12349
|
+
if (!question || !safeDefault || cleaned.length < 2 || cleaned.length > 4 || !seen.has(recommended)) return null;
|
|
12350
|
+
return { question, options: cleaned, recommended_key: recommended, safe_default: safeDefault };
|
|
12351
|
+
}
|
|
12352
|
+
function consensusReceiptIdFrom(text) {
|
|
12353
|
+
const source = String(text ?? "");
|
|
12354
|
+
for (const match of source.matchAll(RECEIPT_RE)) {
|
|
12355
|
+
const token2 = match[1];
|
|
12356
|
+
if (UUID_RE.test(token2)) return token2.toLowerCase();
|
|
12357
|
+
const end = match.index + match[0].length;
|
|
12358
|
+
const probe = `${token2.replace(/[_-]+/gu, " ")} ${source.slice(end, end + 40)}`;
|
|
12359
|
+
if (RECEIPT_NEGATIVE_RE.test(probe)) continue;
|
|
12360
|
+
return token2.slice(0, 120);
|
|
12361
|
+
}
|
|
12362
|
+
return null;
|
|
12363
|
+
}
|
|
12364
|
+
function terminalLedgerPatch(run, nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
12365
|
+
const patch = {};
|
|
12366
|
+
const text = run?.summary;
|
|
12367
|
+
const decision = parseDecisionRequest(text);
|
|
12368
|
+
if (decision) patch.decision_request = { ...decision, requested_at: nowIso };
|
|
12369
|
+
const receipt = consensusReceiptIdFrom(text);
|
|
12370
|
+
if (receipt) patch.consensus_receipt_id = receipt;
|
|
12371
|
+
return patch;
|
|
12372
|
+
}
|
|
12373
|
+
var FENCE_RE, KEY_RE, UUID_RE, RECEIPT_RE, RECEIPT_NEGATIVE_RE, PLACEHOLDER_RE;
|
|
12374
|
+
var init_terminal_ledger_patch = __esm({
|
|
12375
|
+
"../../scripts/virtual-office/code-runner/terminal-ledger-patch.mjs"() {
|
|
12376
|
+
"use strict";
|
|
12377
|
+
FENCE_RE = /```vo-decision-request\s*\n([\s\S]*?)```/iu;
|
|
12378
|
+
KEY_RE = /^[A-D]$/u;
|
|
12379
|
+
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
12380
|
+
RECEIPT_RE = /(?<![A-Za-z0-9_-])(?:consensus[ _-]?)?receipt(?:[ _-]?id)?[`"'*]*\s*[:=#\-\u2013\u2014]\s*[`"'*]*\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|(?:rcpt|cons)[_-][A-Za-z0-9._:-]{4,115})[`"'*]?/giu;
|
|
12381
|
+
RECEIPT_NEGATIVE_RE = /\b(?:not[_-]?available|unavailable|todo|n\/a|none|pending|missing|skipped)\b/iu;
|
|
12382
|
+
PLACEHOLDER_RE = /^[\s.\u2026"'`\-_]*$/u;
|
|
12383
|
+
}
|
|
12384
|
+
});
|
|
12385
|
+
|
|
12251
12386
|
// ../../scripts/virtual-office/code-runner/outcome-commit.mjs
|
|
12252
12387
|
async function beginOutcomeCommit({
|
|
12253
12388
|
client,
|
|
@@ -12557,7 +12692,9 @@ async function finalizePublishedPr({
|
|
|
12557
12692
|
pr_number: pr.prNumber,
|
|
12558
12693
|
pr_branch: pr.branch,
|
|
12559
12694
|
result: partial ? partialPrContinuationResult(run, 2e3, rateLimitResume ? "rate_limited" : null) : String(run.summary).slice(0, 2e3),
|
|
12560
|
-
...runOutcomePatch(run)
|
|
12695
|
+
...runOutcomePatch(run),
|
|
12696
|
+
...terminalLedgerPatch(run)
|
|
12697
|
+
// decision_request / consensus_receipt_id parsed from the agent's final text (2026-08-15)
|
|
12561
12698
|
}
|
|
12562
12699
|
});
|
|
12563
12700
|
if (!posted.accepted) {
|
|
@@ -12592,6 +12729,7 @@ var init_publication_outcome = __esm({
|
|
|
12592
12729
|
init_publish_async();
|
|
12593
12730
|
init_pr_watcher();
|
|
12594
12731
|
init_cancelled_run_report();
|
|
12732
|
+
init_terminal_ledger_patch();
|
|
12595
12733
|
init_process_runner2();
|
|
12596
12734
|
init_outcome_commit();
|
|
12597
12735
|
init_terminal_delivery();
|
|
@@ -12820,8 +12958,8 @@ async function recoverPreservedCodeTask({
|
|
|
12820
12958
|
const token2 = (await client.getInstallationToken({ required: cfg.requireGithubAppAuth }))?.token ?? null;
|
|
12821
12959
|
const run = {
|
|
12822
12960
|
summary: `Recovered preserved work from task ${recovery.originalTaskId}.`,
|
|
12823
|
-
costUsd:
|
|
12824
|
-
costBasis: "
|
|
12961
|
+
costUsd: 0,
|
|
12962
|
+
costBasis: "no_agent_spawned",
|
|
12825
12963
|
executionStarted: false
|
|
12826
12964
|
};
|
|
12827
12965
|
const supersedesPrNumber = supersededSourcePrNumber(recovery.preserved.prompt || task.prompt);
|
|
@@ -13003,7 +13141,9 @@ async function finalizeNoChangesOutcome({
|
|
|
13003
13141
|
// Owns FOUR terminal outcomes: no_changes_needed plus three `failed`
|
|
13004
13142
|
// variants. `failed` is a WASTED_STATUSES member, so usage MUST ride along
|
|
13005
13143
|
// or the waste bucket stays unexplainable.
|
|
13006
|
-
...runOutcomePatch(run)
|
|
13144
|
+
...runOutcomePatch(run),
|
|
13145
|
+
...terminalLedgerPatch(run)
|
|
13146
|
+
// decision_request / consensus_receipt_id parsed from the agent's final text (2026-08-15)
|
|
13007
13147
|
}
|
|
13008
13148
|
});
|
|
13009
13149
|
if (!persisted.accepted) return terminal;
|
|
@@ -13038,6 +13178,7 @@ var init_no_changes_terminal_status = __esm({
|
|
|
13038
13178
|
init_publish();
|
|
13039
13179
|
init_superseded_pr_source();
|
|
13040
13180
|
init_cancelled_run_report();
|
|
13181
|
+
init_terminal_ledger_patch();
|
|
13041
13182
|
init_outcome_commit();
|
|
13042
13183
|
init_terminal_delivery();
|
|
13043
13184
|
RESULT_LIMIT = 2e3;
|
|
@@ -13504,6 +13645,7 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
|
|
|
13504
13645
|
let preserveReason = null;
|
|
13505
13646
|
let attachmentBundle = null;
|
|
13506
13647
|
let run = null;
|
|
13648
|
+
let methodology = null;
|
|
13507
13649
|
let rateLimitResume = null;
|
|
13508
13650
|
try {
|
|
13509
13651
|
if (await recoverPreservedCodeTask({ task, cfg, client, log })) return;
|
|
@@ -13521,6 +13663,9 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
|
|
|
13521
13663
|
const attemptTask = { ...task, max_budget_usd: attemptBudgetUsd };
|
|
13522
13664
|
const { dispatchMode, routerMode, tier, model, permissionMode: effectivePermissionMode, maxTurns: effectiveMaxTurns, effort: effectiveEffort, maxBudgetUsd: effectiveMaxBudgetUsd, prompt: effortPrompt, routerDecision } = await resolveEffortDispatch({ client, task: attemptTask, agent: sel.agent, env: process.env, basePrompt: await composeCodeTaskPrompt(client, task, {
|
|
13523
13665
|
log,
|
|
13666
|
+
onMethodology: (m) => {
|
|
13667
|
+
methodology = m;
|
|
13668
|
+
},
|
|
13524
13669
|
allowMissingKnowledgeContext: process.env.VO_CODE_RUNNER_ALLOW_MISSING_KNOWLEDGE_CONTEXT === "1",
|
|
13525
13670
|
attachmentManifestMarkdown: attachmentBundle.manifestMarkdown
|
|
13526
13671
|
}) });
|
|
@@ -13535,7 +13680,7 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
|
|
|
13535
13680
|
await safeProgress(client, id, runnerStagePatch(
|
|
13536
13681
|
"starting_agent",
|
|
13537
13682
|
`${cfg.runnerId} spawning ${sel.agent}:${model || "default"} (${tier}, effort ${dispatchMode}; ${sel.agent === "claude" ? typeof effectiveMaxBudgetUsd === "number" && effectiveMaxBudgetUsd > 0 ? `$${effectiveMaxBudgetUsd} hard API-equivalent cap` : `no dollar cap, ${effectiveMaxTurns}-turn ceiling` : "20m wall-clock cap"}${routerMode !== "off" && routerDecision ? `; auto-router ${routerMode}: ${routerDecision.rung}${routerDecision.effort ? ` effort=${routerDecision.effort}` : ""}` : ""})`,
|
|
13538
|
-
routerDecision ? { router_decision: routerDecision } : {}
|
|
13683
|
+
{ ...routerDecision ? { router_decision: routerDecision } : {}, ...methodologyLedgerFields(methodology) }
|
|
13539
13684
|
));
|
|
13540
13685
|
const cap = typeof attemptBudgetUsd === "number" ? attemptBudgetUsd : resolveCodeDispatchCapUsd();
|
|
13541
13686
|
run = await runAgentTask({
|
|
@@ -13548,6 +13693,8 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
|
|
|
13548
13693
|
model,
|
|
13549
13694
|
effort: effectiveEffort,
|
|
13550
13695
|
maxBudgetUsd: sel.agent === "claude" ? effectiveMaxBudgetUsd : void 0,
|
|
13696
|
+
researchHarness: methodology?.shape === "research",
|
|
13697
|
+
// Workflow grant only for research-shaped tasks
|
|
13551
13698
|
env: buildAgentProcessEnv(process.env, { agent: sel.agent, runnerId: cfg.runnerId, taskId: id, githubReadToken: agentGithubReadToken, swarmAdmission }),
|
|
13552
13699
|
// swarmAdmission mints VO_SWARM_TIER_BINDING: ONE tier decision for this task's whole agent tree
|
|
13553
13700
|
sandbox,
|
|
@@ -13701,7 +13848,8 @@ Closes #${publicationTarget.supersedesPrNumber}` : "";
|
|
|
13701
13848
|
status: "failed",
|
|
13702
13849
|
message: `runner error: ${msg}`.slice(0, 1500),
|
|
13703
13850
|
result: msg.slice(0, 2e3),
|
|
13704
|
-
...runOutcomePatch(run)
|
|
13851
|
+
...run ? { ...runOutcomePatch(run), ...terminalLedgerPatch(run) } : NO_AGENT_SPAWNED_ECONOMICS
|
|
13852
|
+
// no agent ever spawned ⇒ structural $0, never an unmeasured null; a run that did emit a decision block keeps it
|
|
13705
13853
|
} });
|
|
13706
13854
|
} finally {
|
|
13707
13855
|
try {
|
|
@@ -13746,6 +13894,8 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
13746
13894
|
isRunning: () => !stopping,
|
|
13747
13895
|
startedAt,
|
|
13748
13896
|
log,
|
|
13897
|
+
getClaimGate: () => client.getClaimGate?.() ?? null,
|
|
13898
|
+
// claim-gate verdict on /status (deny-site visibility)
|
|
13749
13899
|
// Single-instance guard: the control-port bind detects an already-serving
|
|
13750
13900
|
// daemon on this machine (see decideAddrInUseAction). Exit 0 so launcher
|
|
13751
13901
|
// respawn loops treat it as a clean stop, not a crash to retry hard.
|
|
@@ -13899,6 +14049,7 @@ var init_code_runner_daemon = __esm({
|
|
|
13899
14049
|
init_recovery_ledger();
|
|
13900
14050
|
init_no_changes_terminal_status();
|
|
13901
14051
|
init_cancelled_run_report();
|
|
14052
|
+
init_terminal_ledger_patch();
|
|
13902
14053
|
init_publication_outcome();
|
|
13903
14054
|
init_outcome_commit();
|
|
13904
14055
|
init_cancellation_probe();
|