@algosuite/vo-mcp 0.2.0-beta.57 → 0.2.0-beta.59
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/runner-cli.js +634 -39
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +252 -15
- package/dist/runner-supervisor.js.map +4 -4
- package/package.json +1 -1
package/dist/runner-cli.js
CHANGED
|
@@ -3666,6 +3666,93 @@ var init_control_plane_knowledge_context = __esm({
|
|
|
3666
3666
|
}
|
|
3667
3667
|
});
|
|
3668
3668
|
|
|
3669
|
+
// ../../scripts/virtual-office/code-runner/control-plane-prepared-job.mjs
|
|
3670
|
+
function preparedJobQuery({ agent = "claude", env: env2 = {} } = {}) {
|
|
3671
|
+
const params = new URLSearchParams();
|
|
3672
|
+
params.set("agent", String(agent));
|
|
3673
|
+
const sent = [];
|
|
3674
|
+
const dropped = [];
|
|
3675
|
+
for (const key of PREPARED_JOB_ENV_QUERY_KEYS) {
|
|
3676
|
+
const raw = env2?.[key];
|
|
3677
|
+
if (typeof raw !== "string" || raw.length === 0) continue;
|
|
3678
|
+
if (raw.length > PREPARED_JOB_ENV_VALUE_MAX) {
|
|
3679
|
+
dropped.push(key);
|
|
3680
|
+
continue;
|
|
3681
|
+
}
|
|
3682
|
+
params.set(key, raw);
|
|
3683
|
+
sent.push(key);
|
|
3684
|
+
}
|
|
3685
|
+
return { query: params.toString(), sent, dropped };
|
|
3686
|
+
}
|
|
3687
|
+
async function refusalCode(res) {
|
|
3688
|
+
try {
|
|
3689
|
+
const body = await res.json();
|
|
3690
|
+
return typeof body?.error === "string" && body.error ? body.error : null;
|
|
3691
|
+
} catch {
|
|
3692
|
+
return null;
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
async function getPreparedJobRequest(req, taskId, options = {}, invalidateToken = () => {
|
|
3696
|
+
}) {
|
|
3697
|
+
const { agent = "claude", env: env2 = {}, timeoutMs = 15e3 } = options;
|
|
3698
|
+
const { query, sent, dropped } = preparedJobQuery({ agent, env: env2 });
|
|
3699
|
+
const envMeta = { envSent: sent, envDropped: dropped };
|
|
3700
|
+
if (typeof taskId !== "string" || taskId.length === 0) {
|
|
3701
|
+
return { ok: false, reason: "missing_task_id", status: 0, ...envMeta };
|
|
3702
|
+
}
|
|
3703
|
+
const path22 = `/api/v1/code-task/${encodeURIComponent(taskId)}/prepared-job?${query}`;
|
|
3704
|
+
let res;
|
|
3705
|
+
try {
|
|
3706
|
+
res = await req("GET", path22, void 0, { timeoutMs });
|
|
3707
|
+
} catch (err) {
|
|
3708
|
+
return { ok: false, reason: `transport: ${err?.message || String(err)}`, status: 0, ...envMeta };
|
|
3709
|
+
}
|
|
3710
|
+
if (res?.status === 401) {
|
|
3711
|
+
try {
|
|
3712
|
+
invalidateToken();
|
|
3713
|
+
} catch {
|
|
3714
|
+
}
|
|
3715
|
+
return { ok: false, reason: "unauthorized", status: 401, ...envMeta };
|
|
3716
|
+
}
|
|
3717
|
+
if (!res?.ok) {
|
|
3718
|
+
const code = await refusalCode(res);
|
|
3719
|
+
return { ok: false, reason: code || `http_${res?.status ?? "unknown"}`, status: res?.status ?? 0, ...envMeta };
|
|
3720
|
+
}
|
|
3721
|
+
let body;
|
|
3722
|
+
try {
|
|
3723
|
+
body = await res.json();
|
|
3724
|
+
} catch (err) {
|
|
3725
|
+
return { ok: false, reason: `unreadable_body: ${err?.message || String(err)}`, status: res.status, ...envMeta };
|
|
3726
|
+
}
|
|
3727
|
+
const job = body?.prepared_job;
|
|
3728
|
+
if (!job || typeof job !== "object") {
|
|
3729
|
+
return { ok: false, reason: "no_prepared_job_in_body", status: res.status, ...envMeta };
|
|
3730
|
+
}
|
|
3731
|
+
return {
|
|
3732
|
+
ok: true,
|
|
3733
|
+
job,
|
|
3734
|
+
composition: body?.composition && typeof body.composition === "object" ? body.composition : {},
|
|
3735
|
+
...envMeta
|
|
3736
|
+
};
|
|
3737
|
+
}
|
|
3738
|
+
var PREPARED_JOB_ENV_QUERY_KEYS, PREPARED_JOB_ENV_VALUE_MAX;
|
|
3739
|
+
var init_control_plane_prepared_job = __esm({
|
|
3740
|
+
"../../scripts/virtual-office/code-runner/control-plane-prepared-job.mjs"() {
|
|
3741
|
+
"use strict";
|
|
3742
|
+
PREPARED_JOB_ENV_QUERY_KEYS = [
|
|
3743
|
+
"VO_CODE_RUNNER_NO_WEB",
|
|
3744
|
+
"VO_CODE_RUNNER_NO_WORKFLOW",
|
|
3745
|
+
"VO_CODE_RUNNER_NO_CONSENSUS",
|
|
3746
|
+
"VO_CODE_RUNNER_PERMISSION_MODE",
|
|
3747
|
+
"VO_CODE_RUNNER_DEFAULT_BUDGET_USD",
|
|
3748
|
+
"VO_CODE_RUNNER_META_REASONING_EFFORT",
|
|
3749
|
+
"VO_CODE_RUNNER_ALLOW_MISSING_KNOWLEDGE_CONTEXT",
|
|
3750
|
+
"VO_ENABLE_CONTEXT7"
|
|
3751
|
+
];
|
|
3752
|
+
PREPARED_JOB_ENV_VALUE_MAX = 64;
|
|
3753
|
+
}
|
|
3754
|
+
});
|
|
3755
|
+
|
|
3669
3756
|
// src/runner/control-plane-auth-stub.mjs
|
|
3670
3757
|
var control_plane_auth_stub_exports = {};
|
|
3671
3758
|
__export(control_plane_auth_stub_exports, {
|
|
@@ -3902,6 +3989,10 @@ function createControlPlaneClient({
|
|
|
3902
3989
|
log: (m) => console.warn(`[code-runner ${(/* @__PURE__ */ new Date()).toISOString()}] ${m}`)
|
|
3903
3990
|
});
|
|
3904
3991
|
},
|
|
3992
|
+
/** ADR-004 § 11.1b: the plane's prepared job, for SHADOW comparison. Never throws. */
|
|
3993
|
+
getPreparedJob: (taskId, options) => getPreparedJobRequest(req, taskId, options, () => {
|
|
3994
|
+
cachedFirebaseToken = null;
|
|
3995
|
+
}),
|
|
3905
3996
|
/** Weekly Claude token usage report — see control-plane-weekly-tokens.mjs. */
|
|
3906
3997
|
async postWeeklyTokens(report) {
|
|
3907
3998
|
return postWeeklyTokensRequest(taskReq, report, () => {
|
|
@@ -3923,8 +4014,8 @@ function createControlPlaneClient({
|
|
|
3923
4014
|
* authenticated operator so the web shows a TRUE "runner online" signal.
|
|
3924
4015
|
* Best-effort caller; throws on 401/non-ok so the daemon can log + retry.
|
|
3925
4016
|
*/
|
|
3926
|
-
async postHeartbeat({ runnerId: runnerId2, runnerInstanceId: runnerInstanceId2, operatorId, uptimeSec, activeTasks, maxConcurrency, effectiveConcurrency, measuredTaskSlots, measuredCpuSlots, measuredMemorySlots, version, daemonVersion, defaultAgent, supervisorInstanceId, supervisorVersion, supervisorCapabilities, servedRepos, servedOperators, availableAgents, accountUsage, availableLocalModels }) {
|
|
3927
|
-
const body = { runner_id: runnerId2 };
|
|
4017
|
+
async postHeartbeat({ runnerId: runnerId2, runnerInstanceId: runnerInstanceId2, operatorId, uptimeSec, activeTasks, maxConcurrency, effectiveConcurrency, measuredTaskSlots, measuredCpuSlots, measuredMemorySlots, version, daemonVersion, defaultAgent, supervisorInstanceId, supervisorVersion, supervisorCapabilities, servedRepos, servedOperators, availableAgents, accountUsage, availableLocalModels, prepared_job_shadow: preparedJobShadow }) {
|
|
4018
|
+
const body = { runner_id: runnerId2, ...preparedJobShadow ? { prepared_job_shadow: preparedJobShadow } : {} };
|
|
3928
4019
|
if (runnerInstanceId2) body.runner_instance_id = runnerInstanceId2;
|
|
3929
4020
|
if (operatorId) body.operator_id = operatorId;
|
|
3930
4021
|
if (typeof uptimeSec === "number") body.uptime_sec = uptimeSec;
|
|
@@ -4055,6 +4146,7 @@ var init_control_plane_client = __esm({
|
|
|
4055
4146
|
init_control_plane_telemetry_relay();
|
|
4056
4147
|
init_claim_gate_notice();
|
|
4057
4148
|
init_control_plane_knowledge_context();
|
|
4149
|
+
init_control_plane_prepared_job();
|
|
4058
4150
|
cachedFirebaseToken = null;
|
|
4059
4151
|
ClaimAuthorityChangedError = class extends Error {
|
|
4060
4152
|
constructor() {
|
|
@@ -7649,8 +7741,17 @@ function messageExcerpt(output) {
|
|
|
7649
7741
|
const s = String(output ?? "");
|
|
7650
7742
|
return s.length > 1200 ? `...${s.slice(-1200)}` : s;
|
|
7651
7743
|
}
|
|
7652
|
-
async function enforceCompletionGateOrFail({
|
|
7653
|
-
|
|
7744
|
+
async function enforceCompletionGateOrFail({
|
|
7745
|
+
client,
|
|
7746
|
+
id,
|
|
7747
|
+
task,
|
|
7748
|
+
worktreeDir,
|
|
7749
|
+
run = null,
|
|
7750
|
+
truncated = false,
|
|
7751
|
+
log: log2 = () => {
|
|
7752
|
+
},
|
|
7753
|
+
execFileImpl = execFile
|
|
7754
|
+
} = {}) {
|
|
7654
7755
|
const resolved = resolveCompletionGate(task);
|
|
7655
7756
|
if (resolved === null) return false;
|
|
7656
7757
|
if (resolved.invalid) {
|
|
@@ -7674,6 +7775,12 @@ ${messageExcerpt(cached2.output)}`, "completion_gate_failed");
|
|
|
7674
7775
|
return false;
|
|
7675
7776
|
}
|
|
7676
7777
|
const kind = outcome.timedOut ? `timed out after ${COMPLETION_GATE_TIMEOUT_MS}ms` : `exited ${outcome.exitCode}`;
|
|
7778
|
+
if (truncated) {
|
|
7779
|
+
log2(`task ${id}: completion gate FAILED (${kind}) after a budget/turn-truncated run \u2014 salvaging as PARTIAL draft, not terminal-failing`);
|
|
7780
|
+
if (run) run.gateFailureNote = `completion gate '${task.completion_gate}' ${kind} (gate ran against a budget/turn-truncated run):
|
|
7781
|
+
${messageExcerpt(outcome.output)}`;
|
|
7782
|
+
return false;
|
|
7783
|
+
}
|
|
7677
7784
|
log2(`task ${id}: completion gate FAILED (${kind}) \u2014 not publishing`);
|
|
7678
7785
|
await postFailed2(client, id, `completion gate '${task.completion_gate}' ${kind} \u2014 task may not claim completion:
|
|
7679
7786
|
${messageExcerpt(outcome.output)}`, "completion_gate_failed");
|
|
@@ -8769,13 +8876,13 @@ async function materializeTaskAttachments(client, task, { tempRoot = os2.tmpdir(
|
|
|
8769
8876
|
const content = await client.downloadTaskAttachment(task.code_task_id, ref.attachment_id);
|
|
8770
8877
|
if (!Buffer.isBuffer(content)) throw new Error(`attachment ${ref.attachment_id} did not return binary content`);
|
|
8771
8878
|
if (content.byteLength !== ref.size_bytes) throw new Error(`attachment ${ref.attachment_id} size mismatch`);
|
|
8772
|
-
const
|
|
8773
|
-
if (
|
|
8879
|
+
const sha2562 = createHash4("sha256").update(content).digest("hex");
|
|
8880
|
+
if (sha2562 !== ref.sha256) throw new Error(`attachment ${ref.attachment_id} sha256 mismatch`);
|
|
8774
8881
|
const name = sanitizeTaskAttachmentName(ref.name, index);
|
|
8775
8882
|
const filePath = path16.join(state.directory, name);
|
|
8776
8883
|
await writeFile(filePath, content, { flag: "wx", mode: 384 });
|
|
8777
8884
|
await chmod(filePath, 384);
|
|
8778
|
-
files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path: path16.resolve(filePath) });
|
|
8885
|
+
files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256: sha2562, path: path16.resolve(filePath) });
|
|
8779
8886
|
}
|
|
8780
8887
|
return { directory: state.directory, files, manifestMarkdown: buildManifest(files), cleanup: () => cleanupGeneratedDirectory(state) };
|
|
8781
8888
|
} catch (error) {
|
|
@@ -9428,6 +9535,13 @@ function makeLoopTicks({
|
|
|
9428
9535
|
applyRemoteConfig: () => false,
|
|
9429
9536
|
heartbeatFields: () => ({})
|
|
9430
9537
|
},
|
|
9538
|
+
// ADR-004 § 11.1b-2: plane-delivered prepared-job consumption mode + the
|
|
9539
|
+
// counts-only shadow tally (prepared-job-remote-config.mjs). Same no-op
|
|
9540
|
+
// default contract as above, so an absent controller changes nothing.
|
|
9541
|
+
preparedJobController = {
|
|
9542
|
+
applyRemoteConfig: () => false,
|
|
9543
|
+
heartbeatFields: () => ({})
|
|
9544
|
+
},
|
|
9431
9545
|
// Host version awareness: reads `update_status` off the heartbeat ACK and logs
|
|
9432
9546
|
// ONE line per drift change (daemon-update-status.mjs). No-op default keeps
|
|
9433
9547
|
// old callers working; absent update_status reads as unknown, never current.
|
|
@@ -9476,6 +9590,7 @@ function makeLoopTicks({
|
|
|
9476
9590
|
request.then((response) => {
|
|
9477
9591
|
capacityController.applyCapacity(response?.capacity, nextPayload.operatorId);
|
|
9478
9592
|
localModelController.applyRemoteConfig(response?.local_model, nextPayload.operatorId);
|
|
9593
|
+
preparedJobController.applyRemoteConfig(response?.prepared_job, nextPayload.operatorId);
|
|
9479
9594
|
updateStatusTracker.applyHeartbeatResponse(response);
|
|
9480
9595
|
}).catch((e) => log2(`heartbeat failed: ${e.message}`)).finally(() => {
|
|
9481
9596
|
for (const done of waiters) done();
|
|
@@ -9520,6 +9635,7 @@ function makeLoopTicks({
|
|
|
9520
9635
|
const supervisorCapabilities = String(env2.VO_RUNNER_SUPERVISOR_CAPABILITIES || "").split(",").map((value) => value.trim()).filter(Boolean).slice(0, 8);
|
|
9521
9636
|
const capacityFields = capacityController.heartbeatFields();
|
|
9522
9637
|
const localModelFields = localModelController.heartbeatFields();
|
|
9638
|
+
const preparedJobFields = preparedJobController.heartbeatFields();
|
|
9523
9639
|
const baseHeartbeat = {
|
|
9524
9640
|
runnerId: cfg.runnerId,
|
|
9525
9641
|
...runnerInstanceId ? { runnerInstanceId } : {},
|
|
@@ -9537,7 +9653,8 @@ function makeLoopTicks({
|
|
|
9537
9653
|
activeTasks: getActive(),
|
|
9538
9654
|
maxConcurrency: cfg.maxConcurrency,
|
|
9539
9655
|
...capacityFields,
|
|
9540
|
-
...localModelFields
|
|
9656
|
+
...localModelFields,
|
|
9657
|
+
...preparedJobFields
|
|
9541
9658
|
};
|
|
9542
9659
|
const operatorIds = servedOperators.length > 0 ? servedOperators : [void 0];
|
|
9543
9660
|
for (const operatorId of operatorIds) {
|
|
@@ -9904,6 +10021,434 @@ var init_local_model_remote_config = __esm({
|
|
|
9904
10021
|
}
|
|
9905
10022
|
});
|
|
9906
10023
|
|
|
10024
|
+
// ../../scripts/virtual-office/code-runner/prepared-job-shadow.mjs
|
|
10025
|
+
import { appendFileSync, mkdirSync as mkdirSync8 } from "node:fs";
|
|
10026
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
10027
|
+
import { homedir as homedir9 } from "node:os";
|
|
10028
|
+
import { dirname as dirname10, join as join14 } from "node:path";
|
|
10029
|
+
function setRemotePreparedJobMode(mode) {
|
|
10030
|
+
const value = typeof mode === "string" ? mode.trim().toLowerCase() : "";
|
|
10031
|
+
remotePreparedJobMode = value && PREPARED_JOB_MODES.includes(value) ? value : "";
|
|
10032
|
+
}
|
|
10033
|
+
function preparedJobConsumptionMode(env2 = process.env) {
|
|
10034
|
+
const raw = String(env2?.[PREPARED_JOB_MODE_ENV] ?? "").trim().toLowerCase();
|
|
10035
|
+
if (raw && PREPARED_JOB_MODES.includes(raw)) return raw;
|
|
10036
|
+
return remotePreparedJobMode || "off";
|
|
10037
|
+
}
|
|
10038
|
+
function shadowTimeoutMs(env2 = process.env) {
|
|
10039
|
+
const n = Number(env2?.[PREPARED_JOB_SHADOW_TIMEOUT_ENV]);
|
|
10040
|
+
return Number.isFinite(n) && n > 0 ? Math.min(n, 6e4) : DEFAULT_SHADOW_TIMEOUT_MS;
|
|
10041
|
+
}
|
|
10042
|
+
function firstDivergenceIndex(a, b) {
|
|
10043
|
+
const A = String(a ?? "");
|
|
10044
|
+
const B = String(b ?? "");
|
|
10045
|
+
const limit = Math.min(A.length, B.length);
|
|
10046
|
+
for (let i = 0; i < limit; i += 1) if (A[i] !== B[i]) return i;
|
|
10047
|
+
return A.length === B.length ? -1 : limit;
|
|
10048
|
+
}
|
|
10049
|
+
function localCompositionAsPreparedJob(local = {}, { agent = "claude", env: env2 = process.env } = {}) {
|
|
10050
|
+
const isClaude = String(agent || "").trim().toLowerCase() === "claude";
|
|
10051
|
+
return {
|
|
10052
|
+
prompt: local.prompt ?? "",
|
|
10053
|
+
argv: buildClaudeArgs({
|
|
10054
|
+
permissionMode: local.permissionMode,
|
|
10055
|
+
maxTurns: isClaude ? local.maxTurns : void 0,
|
|
10056
|
+
model: local.model,
|
|
10057
|
+
effort: local.effort,
|
|
10058
|
+
maxBudgetUsd: isClaude ? local.maxBudgetUsd : void 0,
|
|
10059
|
+
researchHarness: local.methodology?.shape === "research",
|
|
10060
|
+
env: env2
|
|
10061
|
+
}),
|
|
10062
|
+
permission_mode: local.permissionMode ?? null,
|
|
10063
|
+
dispatch_mode: local.dispatchMode ?? null,
|
|
10064
|
+
tier: local.tier ?? null,
|
|
10065
|
+
model: local.model ?? null,
|
|
10066
|
+
effort: local.effort ?? null,
|
|
10067
|
+
max_turns: local.maxTurns ?? null,
|
|
10068
|
+
max_budget_usd: local.maxBudgetUsd ?? null,
|
|
10069
|
+
methodology_shape: local.methodology?.shape ?? null,
|
|
10070
|
+
methodology_stakes: local.methodology?.stakes ?? null
|
|
10071
|
+
};
|
|
10072
|
+
}
|
|
10073
|
+
function planeJobAsComparable(job = {}) {
|
|
10074
|
+
return {
|
|
10075
|
+
prompt: job.prompt ?? "",
|
|
10076
|
+
argv: job.argv ?? null,
|
|
10077
|
+
permission_mode: job.permission_mode ?? null,
|
|
10078
|
+
dispatch_mode: job.dispatch_mode ?? null,
|
|
10079
|
+
tier: job.tier ?? null,
|
|
10080
|
+
model: job.model ?? null,
|
|
10081
|
+
effort: job.effort ?? null,
|
|
10082
|
+
max_turns: job.max_turns ?? null,
|
|
10083
|
+
max_budget_usd: job.max_budget_usd ?? null,
|
|
10084
|
+
methodology_shape: job.methodology?.shape ?? null,
|
|
10085
|
+
methodology_stakes: job.methodology?.stakes ?? null
|
|
10086
|
+
};
|
|
10087
|
+
}
|
|
10088
|
+
function classifyDivergence(field, ctx = {}) {
|
|
10089
|
+
const known = (reason) => ({ class: "known_remainder", reason });
|
|
10090
|
+
if (Array.isArray(ctx.envDropped) && ctx.envDropped.length > 0) {
|
|
10091
|
+
return known(`env_value_too_long:${ctx.envDropped.join("+")}`);
|
|
10092
|
+
}
|
|
10093
|
+
if ((field === "model" || field === "tier") && ctx.planeModelRegistryUnavailable) {
|
|
10094
|
+
return known("no_plane_model_registry");
|
|
10095
|
+
}
|
|
10096
|
+
if (field === "dispatch_mode" && ctx.taskDispatchModeAbsent) return known("plane_dispatch_mode_default");
|
|
10097
|
+
if (ctx.dispatchModeDiverged && DISPATCH_MODE_DEPENDENT.has(field)) {
|
|
10098
|
+
return known("downstream_of_dispatch_mode");
|
|
10099
|
+
}
|
|
10100
|
+
if (field === "prompt" && ctx.attachmentManifestPresent) return known("attachment_manifest_not_sent");
|
|
10101
|
+
if (field === "prompt" && ctx.planeSkillCatalogUnavailable) return known("skill_catalog_unavailable");
|
|
10102
|
+
return { class: "unexplained", reason: null };
|
|
10103
|
+
}
|
|
10104
|
+
function comparePreparedJob({ local, plane, context = {} }) {
|
|
10105
|
+
const L = local || {};
|
|
10106
|
+
const P = plane || {};
|
|
10107
|
+
const raw = COMPARED_FIELDS.filter((f) => !sameValue(L[f], P[f]));
|
|
10108
|
+
const ctx = { ...context, dispatchModeDiverged: raw.includes("dispatch_mode") };
|
|
10109
|
+
const divergences = raw.map((field) => {
|
|
10110
|
+
const { class: cls, reason } = classifyDivergence(field, ctx);
|
|
10111
|
+
const entry = { field, class: cls, reason };
|
|
10112
|
+
if (field !== "prompt") {
|
|
10113
|
+
entry.runner = L[field] ?? null;
|
|
10114
|
+
entry.plane = P[field] ?? null;
|
|
10115
|
+
}
|
|
10116
|
+
return entry;
|
|
10117
|
+
});
|
|
10118
|
+
const unexplainedFields = divergences.filter((d) => d.class === "unexplained").map((d) => d.field);
|
|
10119
|
+
return {
|
|
10120
|
+
verdict: divergences.length === 0 ? "parity_ok" : unexplainedFields.length > 0 ? "parity_diverged" : "parity_known_remainder",
|
|
10121
|
+
divergences,
|
|
10122
|
+
divergentFields: raw,
|
|
10123
|
+
unexplainedFields,
|
|
10124
|
+
prompt: {
|
|
10125
|
+
runner_len: String(L.prompt ?? "").length,
|
|
10126
|
+
plane_len: String(P.prompt ?? "").length,
|
|
10127
|
+
runner_sha256: sha256(L.prompt),
|
|
10128
|
+
plane_sha256: sha256(P.prompt),
|
|
10129
|
+
first_diff_index: firstDivergenceIndex(L.prompt, P.prompt)
|
|
10130
|
+
}
|
|
10131
|
+
};
|
|
10132
|
+
}
|
|
10133
|
+
function selectDispatchComposition({ mode, local, plane, comparison }) {
|
|
10134
|
+
if (mode === "prepared" && plane && comparison?.verdict !== "unavailable") {
|
|
10135
|
+
return { source: "plane", composition: plane };
|
|
10136
|
+
}
|
|
10137
|
+
return { source: "local", composition: local };
|
|
10138
|
+
}
|
|
10139
|
+
function buildShadowRecord({
|
|
10140
|
+
taskId,
|
|
10141
|
+
repo,
|
|
10142
|
+
agent,
|
|
10143
|
+
mode,
|
|
10144
|
+
comparison,
|
|
10145
|
+
fetched,
|
|
10146
|
+
ts
|
|
10147
|
+
}) {
|
|
10148
|
+
const base = {
|
|
10149
|
+
schema_version: 1,
|
|
10150
|
+
kind: "prepared_job_shadow",
|
|
10151
|
+
adr: "ADR-004 \xA7 11.1b",
|
|
10152
|
+
ts,
|
|
10153
|
+
code_task_id: taskId ?? null,
|
|
10154
|
+
repo: repo ?? null,
|
|
10155
|
+
agent: agent ?? null,
|
|
10156
|
+
mode,
|
|
10157
|
+
env_sent: fetched?.envSent ?? [],
|
|
10158
|
+
env_dropped: fetched?.envDropped ?? []
|
|
10159
|
+
};
|
|
10160
|
+
if (!comparison) {
|
|
10161
|
+
return {
|
|
10162
|
+
...base,
|
|
10163
|
+
verdict: "unavailable",
|
|
10164
|
+
reason: fetched?.reason ?? "unknown",
|
|
10165
|
+
status: fetched?.status ?? 0,
|
|
10166
|
+
divergent_fields: [],
|
|
10167
|
+
unexplained_fields: [],
|
|
10168
|
+
divergences: []
|
|
10169
|
+
};
|
|
10170
|
+
}
|
|
10171
|
+
return {
|
|
10172
|
+
...base,
|
|
10173
|
+
verdict: comparison.verdict,
|
|
10174
|
+
reason: null,
|
|
10175
|
+
divergent_fields: comparison.divergentFields,
|
|
10176
|
+
unexplained_fields: comparison.unexplainedFields,
|
|
10177
|
+
divergences: comparison.divergences,
|
|
10178
|
+
prompt: comparison.prompt,
|
|
10179
|
+
plane_composition: {
|
|
10180
|
+
model_registry: fetched?.composition?.model_registry ?? null,
|
|
10181
|
+
skill_catalog_available: fetched?.composition?.skill_catalog_available ?? null
|
|
10182
|
+
}
|
|
10183
|
+
};
|
|
10184
|
+
}
|
|
10185
|
+
function formatShadowLogLine(record) {
|
|
10186
|
+
const parts = [
|
|
10187
|
+
`task=${record.code_task_id}`,
|
|
10188
|
+
`mode=${record.mode}`,
|
|
10189
|
+
`verdict=${record.verdict}`
|
|
10190
|
+
];
|
|
10191
|
+
if (record.verdict === "unavailable") parts.push(`reason=${record.reason}`, `status=${record.status}`);
|
|
10192
|
+
if (record.unexplained_fields?.length) parts.push(`UNEXPLAINED=${record.unexplained_fields.join(",")}`);
|
|
10193
|
+
const known = (record.divergences || []).filter((d) => d.class === "known_remainder");
|
|
10194
|
+
if (known.length) parts.push(`known=${known.map((d) => `${d.field}(${d.reason})`).join(",")}`);
|
|
10195
|
+
if (record.verdict === "parity_diverged" && typeof record.prompt?.first_diff_index === "number" && record.prompt.first_diff_index >= 0 && record.unexplained_fields?.includes("prompt")) {
|
|
10196
|
+
parts.push(`prompt_first_diff_index=${record.prompt.first_diff_index}`);
|
|
10197
|
+
}
|
|
10198
|
+
const loud = record.unexplained_fields?.length ? "!! " : "";
|
|
10199
|
+
return `${loud}[prepared-job-shadow] ${parts.join(" ")}`;
|
|
10200
|
+
}
|
|
10201
|
+
function appendShadowRecord(record, { path: path22 = PREPARED_JOB_SHADOW_SINK, append = appendFileSync, mkdir: mkdir5 = mkdirSync8 } = {}) {
|
|
10202
|
+
try {
|
|
10203
|
+
mkdir5(dirname10(path22), { recursive: true });
|
|
10204
|
+
append(path22, `${JSON.stringify(record)}
|
|
10205
|
+
`, "utf8");
|
|
10206
|
+
return true;
|
|
10207
|
+
} catch {
|
|
10208
|
+
return false;
|
|
10209
|
+
}
|
|
10210
|
+
}
|
|
10211
|
+
async function preparedJobShadowPass({
|
|
10212
|
+
client,
|
|
10213
|
+
task,
|
|
10214
|
+
agent = "claude",
|
|
10215
|
+
env: env2 = process.env,
|
|
10216
|
+
local,
|
|
10217
|
+
log: log2 = () => {
|
|
10218
|
+
},
|
|
10219
|
+
now = () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
10220
|
+
sinkOptions
|
|
10221
|
+
} = {}) {
|
|
10222
|
+
const mode = preparedJobConsumptionMode(env2);
|
|
10223
|
+
if (mode === "off") return { mode: "off" };
|
|
10224
|
+
try {
|
|
10225
|
+
if (mode === "prepared") {
|
|
10226
|
+
log2("[prepared-job-shadow] prepared_mode_not_wired \u2014 comparing only; ADR-004 \xA7 11.1c owns the flip");
|
|
10227
|
+
}
|
|
10228
|
+
if (typeof client?.getPreparedJob !== "function") {
|
|
10229
|
+
return { mode, verdict: "unavailable", reason: "client_lacks_get_prepared_job" };
|
|
10230
|
+
}
|
|
10231
|
+
const fetched = await client.getPreparedJob(task?.code_task_id, {
|
|
10232
|
+
agent,
|
|
10233
|
+
env: env2,
|
|
10234
|
+
timeoutMs: shadowTimeoutMs(env2)
|
|
10235
|
+
});
|
|
10236
|
+
const localJob = localCompositionAsPreparedJob(local, { agent, env: env2 });
|
|
10237
|
+
const comparison = fetched?.ok ? comparePreparedJob({
|
|
10238
|
+
local: localJob,
|
|
10239
|
+
plane: planeJobAsComparable(fetched.job),
|
|
10240
|
+
context: {
|
|
10241
|
+
planeModelRegistryUnavailable: fetched.composition?.model_registry !== "injected",
|
|
10242
|
+
planeSkillCatalogUnavailable: fetched.composition?.skill_catalog_available === false,
|
|
10243
|
+
taskDispatchModeAbsent: !task?.dispatch_mode,
|
|
10244
|
+
attachmentManifestPresent: Boolean(local?.attachmentManifestMarkdown),
|
|
10245
|
+
envDropped: fetched.envDropped
|
|
10246
|
+
}
|
|
10247
|
+
}) : null;
|
|
10248
|
+
const record = buildShadowRecord({
|
|
10249
|
+
taskId: task?.code_task_id,
|
|
10250
|
+
repo: task?.repo,
|
|
10251
|
+
agent,
|
|
10252
|
+
mode,
|
|
10253
|
+
comparison,
|
|
10254
|
+
fetched,
|
|
10255
|
+
ts: now()
|
|
10256
|
+
});
|
|
10257
|
+
appendShadowRecord(record, sinkOptions);
|
|
10258
|
+
log2(formatShadowLogLine(record));
|
|
10259
|
+
return {
|
|
10260
|
+
mode,
|
|
10261
|
+
verdict: record.verdict,
|
|
10262
|
+
record,
|
|
10263
|
+
selection: selectDispatchComposition({
|
|
10264
|
+
mode,
|
|
10265
|
+
local: localJob,
|
|
10266
|
+
plane: fetched?.ok ? planeJobAsComparable(fetched.job) : null,
|
|
10267
|
+
comparison
|
|
10268
|
+
})
|
|
10269
|
+
};
|
|
10270
|
+
} catch (err) {
|
|
10271
|
+
try {
|
|
10272
|
+
log2(`[prepared-job-shadow] shadow pass failed (dispatch unaffected): ${err?.message || err}`);
|
|
10273
|
+
} catch {
|
|
10274
|
+
}
|
|
10275
|
+
return { mode, verdict: "unavailable", reason: `shadow_error: ${err?.message || String(err)}` };
|
|
10276
|
+
}
|
|
10277
|
+
}
|
|
10278
|
+
function setPreparedJobShadowObserver(fn) {
|
|
10279
|
+
verdictObserver = typeof fn === "function" ? fn : null;
|
|
10280
|
+
}
|
|
10281
|
+
async function runPreparedJobShadow(options = {}) {
|
|
10282
|
+
const result = await preparedJobShadowPass(options);
|
|
10283
|
+
try {
|
|
10284
|
+
verdictObserver?.(result);
|
|
10285
|
+
} catch {
|
|
10286
|
+
}
|
|
10287
|
+
return result;
|
|
10288
|
+
}
|
|
10289
|
+
var PREPARED_JOB_MODES, PREPARED_JOB_MODE_ENV, PREPARED_JOB_SHADOW_TIMEOUT_ENV, DEFAULT_SHADOW_TIMEOUT_MS, PREPARED_JOB_SHADOW_SINK, remotePreparedJobMode, COMPARED_FIELDS, DISPATCH_MODE_DEPENDENT, sha256, sameValue, verdictObserver;
|
|
10290
|
+
var init_prepared_job_shadow = __esm({
|
|
10291
|
+
"../../scripts/virtual-office/code-runner/prepared-job-shadow.mjs"() {
|
|
10292
|
+
"use strict";
|
|
10293
|
+
init_claude_args();
|
|
10294
|
+
PREPARED_JOB_MODES = ["off", "shadow", "prepared"];
|
|
10295
|
+
PREPARED_JOB_MODE_ENV = "VO_CODE_RUNNER_PREPARED_JOB";
|
|
10296
|
+
PREPARED_JOB_SHADOW_TIMEOUT_ENV = "VO_PREPARED_JOB_SHADOW_TIMEOUT_MS";
|
|
10297
|
+
DEFAULT_SHADOW_TIMEOUT_MS = 15e3;
|
|
10298
|
+
PREPARED_JOB_SHADOW_SINK = join14(homedir9(), ".claude", "vo-prepared-job-shadow.jsonl");
|
|
10299
|
+
remotePreparedJobMode = "";
|
|
10300
|
+
COMPARED_FIELDS = [
|
|
10301
|
+
"prompt",
|
|
10302
|
+
"argv",
|
|
10303
|
+
"permission_mode",
|
|
10304
|
+
"dispatch_mode",
|
|
10305
|
+
"tier",
|
|
10306
|
+
"model",
|
|
10307
|
+
"effort",
|
|
10308
|
+
"max_turns",
|
|
10309
|
+
"max_budget_usd",
|
|
10310
|
+
"methodology_shape",
|
|
10311
|
+
"methodology_stakes"
|
|
10312
|
+
];
|
|
10313
|
+
DISPATCH_MODE_DEPENDENT = /* @__PURE__ */ new Set([
|
|
10314
|
+
"prompt",
|
|
10315
|
+
"argv",
|
|
10316
|
+
"permission_mode",
|
|
10317
|
+
"tier",
|
|
10318
|
+
"model",
|
|
10319
|
+
"effort",
|
|
10320
|
+
"max_turns"
|
|
10321
|
+
]);
|
|
10322
|
+
sha256 = (s) => createHash6("sha256").update(String(s ?? ""), "utf8").digest("hex");
|
|
10323
|
+
sameValue = (a, b) => Array.isArray(a) || Array.isArray(b) ? JSON.stringify(a) === JSON.stringify(b) : (a ?? null) === (b ?? null);
|
|
10324
|
+
verdictObserver = null;
|
|
10325
|
+
}
|
|
10326
|
+
});
|
|
10327
|
+
|
|
10328
|
+
// ../../scripts/virtual-office/code-runner/prepared-job-remote-config.mjs
|
|
10329
|
+
function emptyPreparedJobTally() {
|
|
10330
|
+
return {
|
|
10331
|
+
compared: 0,
|
|
10332
|
+
parity_ok: 0,
|
|
10333
|
+
parity_diverged: 0,
|
|
10334
|
+
unavailable: 0,
|
|
10335
|
+
unexplained: 0,
|
|
10336
|
+
diverged_fields: {},
|
|
10337
|
+
last_verdict_at: null
|
|
10338
|
+
};
|
|
10339
|
+
}
|
|
10340
|
+
function foldPreparedJobVerdict(tally, result, nowIso) {
|
|
10341
|
+
const verdict = result?.verdict;
|
|
10342
|
+
if (!verdict) return tally;
|
|
10343
|
+
tally.last_verdict_at = nowIso;
|
|
10344
|
+
if (verdict === "unavailable") {
|
|
10345
|
+
tally.unavailable += 1;
|
|
10346
|
+
return tally;
|
|
10347
|
+
}
|
|
10348
|
+
tally.compared += 1;
|
|
10349
|
+
if (verdict === "parity_ok") tally.parity_ok += 1;
|
|
10350
|
+
else if (verdict === "parity_diverged") tally.parity_diverged += 1;
|
|
10351
|
+
const record = result.record || {};
|
|
10352
|
+
tally.unexplained += (record.unexplained_fields || []).length;
|
|
10353
|
+
for (const field of record.divergent_fields || []) {
|
|
10354
|
+
const known = Object.prototype.hasOwnProperty.call(tally.diverged_fields, field);
|
|
10355
|
+
if (!known && Object.keys(tally.diverged_fields).length >= MAX_DIVERGED_FIELD_KEYS) continue;
|
|
10356
|
+
tally.diverged_fields[field] = (tally.diverged_fields[field] || 0) + 1;
|
|
10357
|
+
}
|
|
10358
|
+
return tally;
|
|
10359
|
+
}
|
|
10360
|
+
function createPreparedJobRemoteController({
|
|
10361
|
+
log: log2 = () => {
|
|
10362
|
+
},
|
|
10363
|
+
now = () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
10364
|
+
apply = setRemotePreparedJobMode,
|
|
10365
|
+
observe = setPreparedJobShadowObserver
|
|
10366
|
+
} = {}) {
|
|
10367
|
+
const byOperator = /* @__PURE__ */ new Map();
|
|
10368
|
+
const tally = emptyPreparedJobTally();
|
|
10369
|
+
let planeSpeaksPreparedJob = false;
|
|
10370
|
+
let warnedNotWired = false;
|
|
10371
|
+
let warnedConflict = "";
|
|
10372
|
+
function desiredMode() {
|
|
10373
|
+
const modes = [...new Set(
|
|
10374
|
+
[...byOperator.values()].map((s) => s.mode).filter((m) => m && m !== "off")
|
|
10375
|
+
)];
|
|
10376
|
+
if (modes.length > 1) {
|
|
10377
|
+
const key = modes.slice().sort().join(",");
|
|
10378
|
+
if (warnedConflict !== key) {
|
|
10379
|
+
warnedConflict = key;
|
|
10380
|
+
log2(`prepared-job remote config: conflicting modes across served operators (${key}) \u2014 applying off`);
|
|
10381
|
+
}
|
|
10382
|
+
return "off";
|
|
10383
|
+
}
|
|
10384
|
+
return modes[0] ?? "off";
|
|
10385
|
+
}
|
|
10386
|
+
function syncEffective() {
|
|
10387
|
+
const mode = desiredMode();
|
|
10388
|
+
apply(mode);
|
|
10389
|
+
return mode;
|
|
10390
|
+
}
|
|
10391
|
+
observe((result) => foldPreparedJobVerdict(tally, result, now()));
|
|
10392
|
+
return {
|
|
10393
|
+
/**
|
|
10394
|
+
* Heartbeat payload extras. Silent until the plane has proven it speaks this
|
|
10395
|
+
* contract AND a pass has actually been counted — see safety property 3.
|
|
10396
|
+
*/
|
|
10397
|
+
heartbeatFields() {
|
|
10398
|
+
if (!planeSpeaksPreparedJob || tally.last_verdict_at === null) return {};
|
|
10399
|
+
return {
|
|
10400
|
+
prepared_job_shadow: {
|
|
10401
|
+
schema_version: PREPARED_JOB_CONFIG_SCHEMA_VERSION,
|
|
10402
|
+
mode: desiredMode(),
|
|
10403
|
+
...tally,
|
|
10404
|
+
diverged_fields: { ...tally.diverged_fields }
|
|
10405
|
+
}
|
|
10406
|
+
};
|
|
10407
|
+
},
|
|
10408
|
+
/**
|
|
10409
|
+
* Apply one operator's heartbeat-response echo
|
|
10410
|
+
* `{ schema_version, prepared_job_mode, revision }`. Returns whether the
|
|
10411
|
+
* echo was accepted.
|
|
10412
|
+
*/
|
|
10413
|
+
applyRemoteConfig(echo, operatorId = "") {
|
|
10414
|
+
const scope = String(operatorId || "");
|
|
10415
|
+
const previous = byOperator.get(scope);
|
|
10416
|
+
if (!echo || echo.schema_version !== PREPARED_JOB_CONFIG_SCHEMA_VERSION || !Number.isInteger(echo.revision) || previous && echo.revision < previous.revision) {
|
|
10417
|
+
return false;
|
|
10418
|
+
}
|
|
10419
|
+
const raw = typeof echo.prepared_job_mode === "string" ? echo.prepared_job_mode.trim().toLowerCase() : "";
|
|
10420
|
+
if (!PREPARED_JOB_MODES.includes(raw)) return false;
|
|
10421
|
+
planeSpeaksPreparedJob = true;
|
|
10422
|
+
let mode = raw;
|
|
10423
|
+
if (mode === "prepared") {
|
|
10424
|
+
mode = "shadow";
|
|
10425
|
+
if (!warnedNotWired) {
|
|
10426
|
+
warnedNotWired = true;
|
|
10427
|
+
log2("prepared-job remote config: prepared_mode_not_wired \u2014 applying shadow; ADR-004 \xA7 11.1c owns the flip");
|
|
10428
|
+
}
|
|
10429
|
+
}
|
|
10430
|
+
byOperator.set(scope, { revision: echo.revision, mode });
|
|
10431
|
+
syncEffective();
|
|
10432
|
+
return true;
|
|
10433
|
+
},
|
|
10434
|
+
snapshot: () => ({
|
|
10435
|
+
mode: desiredMode(),
|
|
10436
|
+
planeSpeaksPreparedJob,
|
|
10437
|
+
tally: { ...tally, diverged_fields: { ...tally.diverged_fields } },
|
|
10438
|
+
operators: Object.fromEntries(byOperator)
|
|
10439
|
+
})
|
|
10440
|
+
};
|
|
10441
|
+
}
|
|
10442
|
+
var PREPARED_JOB_CONFIG_SCHEMA_VERSION, MAX_DIVERGED_FIELD_KEYS;
|
|
10443
|
+
var init_prepared_job_remote_config = __esm({
|
|
10444
|
+
"../../scripts/virtual-office/code-runner/prepared-job-remote-config.mjs"() {
|
|
10445
|
+
"use strict";
|
|
10446
|
+
init_prepared_job_shadow();
|
|
10447
|
+
PREPARED_JOB_CONFIG_SCHEMA_VERSION = 1;
|
|
10448
|
+
MAX_DIVERGED_FIELD_KEYS = 24;
|
|
10449
|
+
}
|
|
10450
|
+
});
|
|
10451
|
+
|
|
9907
10452
|
// ../../scripts/virtual-office/code-runner/account-usage/shared.mjs
|
|
9908
10453
|
import crypto from "node:crypto";
|
|
9909
10454
|
import fs9 from "node:fs";
|
|
@@ -10524,7 +11069,7 @@ var init_error_message = __esm({
|
|
|
10524
11069
|
});
|
|
10525
11070
|
|
|
10526
11071
|
// ../../scripts/virtual-office/code-runner/watcher-coordination.mjs
|
|
10527
|
-
import { createHash as
|
|
11072
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
10528
11073
|
function ciFixOccurrenceKey({ repo, prNumber, headSha, repairAttempt }) {
|
|
10529
11074
|
const occurrence = JSON.stringify([
|
|
10530
11075
|
String(repo).toLowerCase(),
|
|
@@ -10532,7 +11077,7 @@ function ciFixOccurrenceKey({ repo, prNumber, headSha, repairAttempt }) {
|
|
|
10532
11077
|
String(headSha).toLowerCase(),
|
|
10533
11078
|
Number(repairAttempt)
|
|
10534
11079
|
]);
|
|
10535
|
-
return `ci-fix:v1:${
|
|
11080
|
+
return `ci-fix:v1:${createHash7("sha256").update(occurrence).digest("hex")}`;
|
|
10536
11081
|
}
|
|
10537
11082
|
function coordinationRetryDue(entry, nowMs) {
|
|
10538
11083
|
return !entry.nextRetryAt || nowMs >= entry.nextRetryAt;
|
|
@@ -10664,7 +11209,7 @@ var init_watcher_coordination = __esm({
|
|
|
10664
11209
|
// ../../scripts/virtual-office/code-runner/watcher-state.mjs
|
|
10665
11210
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
10666
11211
|
import { mkdir as mkdir3, open as open2, readFile as readFile4, rename, unlink as unlink2 } from "node:fs/promises";
|
|
10667
|
-
import { dirname as
|
|
11212
|
+
import { dirname as dirname11 } from "node:path";
|
|
10668
11213
|
async function readWatcherState(stateFile) {
|
|
10669
11214
|
let raw;
|
|
10670
11215
|
try {
|
|
@@ -10680,7 +11225,7 @@ async function readWatcherState(stateFile) {
|
|
|
10680
11225
|
return parsed;
|
|
10681
11226
|
}
|
|
10682
11227
|
async function writeWatcherState(stateFile, state) {
|
|
10683
|
-
const directory =
|
|
11228
|
+
const directory = dirname11(stateFile);
|
|
10684
11229
|
await mkdir3(directory, { recursive: true });
|
|
10685
11230
|
const temp = `${stateFile}.${process.pid}.${randomUUID4()}.tmp`;
|
|
10686
11231
|
let handle;
|
|
@@ -11142,8 +11687,8 @@ var init_pr_watcher_github = __esm({
|
|
|
11142
11687
|
"../../scripts/virtual-office/code-runner/pr-watcher-github.mjs"() {
|
|
11143
11688
|
"use strict";
|
|
11144
11689
|
init_process_runner2();
|
|
11145
|
-
VIEW_FIELDS_WITH_CI = "state,statusCheckRollup,headRefName,headRefOid,url,isDraft,mergeStateStatus";
|
|
11146
|
-
VIEW_FIELDS_WITHOUT_CI = "state,headRefName,headRefOid,url,isDraft,mergeStateStatus";
|
|
11690
|
+
VIEW_FIELDS_WITH_CI = "state,statusCheckRollup,headRefName,headRefOid,url,isDraft,mergeStateStatus,body";
|
|
11691
|
+
VIEW_FIELDS_WITHOUT_CI = "state,headRefName,headRefOid,url,isDraft,mergeStateStatus,body";
|
|
11147
11692
|
CI_UNREADABLE_REASON = "app_token_missing_checks_read";
|
|
11148
11693
|
DIAGNOSTIC_INTERVAL_MS = 30 * 60 * 1e3;
|
|
11149
11694
|
lastDiagnosticAt = 0;
|
|
@@ -11209,8 +11754,8 @@ var init_enqueue_autonomous_code_task = __esm({
|
|
|
11209
11754
|
});
|
|
11210
11755
|
|
|
11211
11756
|
// ../../scripts/virtual-office/code-runner/pr-watcher.mjs
|
|
11212
|
-
import { homedir as
|
|
11213
|
-
import { join as
|
|
11757
|
+
import { homedir as homedir10 } from "node:os";
|
|
11758
|
+
import { join as join15 } from "node:path";
|
|
11214
11759
|
function parsePrCiStatus(view) {
|
|
11215
11760
|
const state = (view && typeof view.state === "string" ? view.state : "UNKNOWN").toUpperCase();
|
|
11216
11761
|
const rollup = latestCheckRunsByName(view && Array.isArray(view.statusCheckRollup) ? view.statusCheckRollup : []);
|
|
@@ -11582,7 +12127,7 @@ var init_pr_watcher = __esm({
|
|
|
11582
12127
|
init_watcher_merge_authority();
|
|
11583
12128
|
init_superseded_pr_source();
|
|
11584
12129
|
init_ci_fix_prompt();
|
|
11585
|
-
DEFAULT_STATE_FILE =
|
|
12130
|
+
DEFAULT_STATE_FILE = join15(homedir10(), ".vo", "dispatched-prs.json");
|
|
11586
12131
|
FAIL_CONCLUSIONS = /* @__PURE__ */ new Set([
|
|
11587
12132
|
"FAILURE",
|
|
11588
12133
|
"TIMED_OUT",
|
|
@@ -11885,7 +12430,7 @@ function startControlServer({ port, getStatus, requestStop, allowedOrigin, log:
|
|
|
11885
12430
|
server.unref?.();
|
|
11886
12431
|
return server;
|
|
11887
12432
|
}
|
|
11888
|
-
function startDaemonControl({ cfg, runnerInstanceId, requestStop, getActiveCount, isRunning, startedAt, log: log2 = () => {
|
|
12433
|
+
function startDaemonControl({ cfg, runnerInstanceId, requestStop, getActiveCount, getActiveTaskIds = () => [], isRunning, startedAt, log: log2 = () => {
|
|
11889
12434
|
}, onDuplicate = null, getUpdateStatus = () => null, getClaimGate = () => null }) {
|
|
11890
12435
|
if (!cfg.controlEnabled) return null;
|
|
11891
12436
|
return startControlServer({
|
|
@@ -11902,6 +12447,9 @@ function startDaemonControl({ cfg, runnerInstanceId, requestStop, getActiveCount
|
|
|
11902
12447
|
servedOperators: cfg.servedOperators,
|
|
11903
12448
|
watchEnabled: cfg.watchEnabled,
|
|
11904
12449
|
activeTasks: getActiveCount(),
|
|
12450
|
+
// The supervisor's update-drain gate reads THESE ids (not a guess) to mark
|
|
12451
|
+
// in-flight work before a capped staged-update restart kills it.
|
|
12452
|
+
activeTaskIds: getActiveTaskIds(),
|
|
11905
12453
|
startedAt: new Date(startedAt).toISOString(),
|
|
11906
12454
|
uptimeSec: Math.round((Date.now() - startedAt) / 1e3),
|
|
11907
12455
|
// Host version awareness — the app + `runner --status` read drift from here.
|
|
@@ -12353,13 +12901,13 @@ async function resolveModelForTier(tier, { agent = DEFAULT_AGENT2, resolveModelF
|
|
|
12353
12901
|
if (resolved && modelCompatibleWithAgent(normalizedAgent, resolved)) return resolved;
|
|
12354
12902
|
return fallbacks[effectiveTier];
|
|
12355
12903
|
}
|
|
12356
|
-
async function resolveTaskModel(task, { agent = DEFAULT_AGENT2 } = {}) {
|
|
12904
|
+
async function resolveTaskModel(task, { agent = DEFAULT_AGENT2, resolveModelFamily: resolver = resolveModelFamily } = {}) {
|
|
12357
12905
|
const tier = task.tier && task.tier !== "auto" ? task.tier : classifyTier2(task.prompt);
|
|
12358
12906
|
const pinned = typeof task.model === "string" ? task.model.trim() : "";
|
|
12359
12907
|
if (pinned && modelCompatibleWithAgent(normalizeAgent(agent), pinned)) {
|
|
12360
12908
|
return { tier, model: pinned };
|
|
12361
12909
|
}
|
|
12362
|
-
const model = await resolveModelForTier(tier, { agent });
|
|
12910
|
+
const model = await resolveModelForTier(tier, { agent, resolveModelFamily: resolver });
|
|
12363
12911
|
return { tier, model };
|
|
12364
12912
|
}
|
|
12365
12913
|
var TASK_MODEL_AGENTS, DEFAULT_AGENT2, AGENT_TIER_FAMILIES, AGENT_TIER_FALLBACKS, AGENT_MODEL_COMPATIBILITY;
|
|
@@ -12826,8 +13374,8 @@ var init_classify_task = __esm({
|
|
|
12826
13374
|
|
|
12827
13375
|
// ../../scripts/virtual-office/code-runner/auto-router/effort-policy.mjs
|
|
12828
13376
|
import { readFileSync as readFileSync9 } from "node:fs";
|
|
12829
|
-
import { homedir as
|
|
12830
|
-
import { join as
|
|
13377
|
+
import { homedir as homedir11 } from "node:os";
|
|
13378
|
+
import { join as join16 } from "node:path";
|
|
12831
13379
|
function difficultyToRung(difficulty, thresholds) {
|
|
12832
13380
|
const b = thresholds.rungBounds;
|
|
12833
13381
|
if (difficulty >= b.R5) return "R5";
|
|
@@ -12904,7 +13452,7 @@ var init_effort_policy = __esm({
|
|
|
12904
13452
|
init_meta_model_catalog();
|
|
12905
13453
|
RUNG_ORDER = ["R1", "R2", "R3", "R4", "R5"];
|
|
12906
13454
|
rungIndex = (rung) => RUNG_ORDER.indexOf(rung);
|
|
12907
|
-
DEFAULT_CODEX_MODELS_CACHE =
|
|
13455
|
+
DEFAULT_CODEX_MODELS_CACHE = join16(homedir11(), ".codex", "models_cache.json");
|
|
12908
13456
|
}
|
|
12909
13457
|
});
|
|
12910
13458
|
|
|
@@ -13034,9 +13582,9 @@ var init_role_cost_shadow = __esm({
|
|
|
13034
13582
|
});
|
|
13035
13583
|
|
|
13036
13584
|
// ../../scripts/virtual-office/code-runner/auto-router/auto-router.mjs
|
|
13037
|
-
import { readFileSync as readFileSync10, appendFileSync, mkdirSync as
|
|
13038
|
-
import { homedir as
|
|
13039
|
-
import { join as
|
|
13585
|
+
import { readFileSync as readFileSync10, appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "node:fs";
|
|
13586
|
+
import { homedir as homedir12 } from "node:os";
|
|
13587
|
+
import { join as join17, dirname as dirname12 } from "node:path";
|
|
13040
13588
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
13041
13589
|
function getAutoRouterMode(env2 = process.env) {
|
|
13042
13590
|
const raw = String(env2.VO_CODE_RUNNER_AUTO_ROUTER || "").trim().toLowerCase();
|
|
@@ -13044,8 +13592,8 @@ function getAutoRouterMode(env2 = process.env) {
|
|
|
13044
13592
|
}
|
|
13045
13593
|
function loadThresholds() {
|
|
13046
13594
|
if (!cachedThresholds) {
|
|
13047
|
-
const here =
|
|
13048
|
-
cachedThresholds = JSON.parse(readFileSync10(
|
|
13595
|
+
const here = dirname12(fileURLToPath7(import.meta.url));
|
|
13596
|
+
cachedThresholds = JSON.parse(readFileSync10(join17(here, "thresholds.json"), "utf8"));
|
|
13049
13597
|
}
|
|
13050
13598
|
return cachedThresholds;
|
|
13051
13599
|
}
|
|
@@ -13111,9 +13659,9 @@ function formatDecisionReason(decision, maxLen = 480) {
|
|
|
13111
13659
|
const s = `[${decision.routerVersion}] ${decision.taskClass} d=${decision.difficulty} c=${decision.confidence} \u2192 ${decision.rung}/${decision.tier}${decision.effort ? ` effort=${decision.effort}` : ""} turns=${decision.maxTurns} $${decision.maxBudgetUsd}${decision.flags.length ? ` [${decision.flags.join(",")}]` : ""} :: ${decision.reasons.join("; ")}`;
|
|
13112
13660
|
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
13113
13661
|
}
|
|
13114
|
-
function appendDecisionFallback(decision, { path: path22 = DECISION_FALLBACK_PATH, append =
|
|
13662
|
+
function appendDecisionFallback(decision, { path: path22 = DECISION_FALLBACK_PATH, append = appendFileSync2, mkdir: mkdir5 = mkdirSync9, task, thresholds, roleCostInputs } = {}) {
|
|
13115
13663
|
try {
|
|
13116
|
-
mkdir5(
|
|
13664
|
+
mkdir5(dirname12(path22), { recursive: true });
|
|
13117
13665
|
append(path22, `${JSON.stringify(decision)}
|
|
13118
13666
|
`, "utf8");
|
|
13119
13667
|
if (isRouterDecision(decision)) {
|
|
@@ -13137,7 +13685,7 @@ var init_auto_router = __esm({
|
|
|
13137
13685
|
init_effort_policy();
|
|
13138
13686
|
init_role_cost_shadow();
|
|
13139
13687
|
ROUTER_VERSION = "0.1.0";
|
|
13140
|
-
DECISION_FALLBACK_PATH =
|
|
13688
|
+
DECISION_FALLBACK_PATH = join17(homedir12(), ".claude", "vo-auto-router-decisions.jsonl");
|
|
13141
13689
|
MODES = /* @__PURE__ */ new Set(["off", "shadow", "on"]);
|
|
13142
13690
|
cachedThresholds = null;
|
|
13143
13691
|
isRouterDecision = (d) => Boolean(d && typeof d === "object" && typeof d.taskClass === "string" && typeof d.confidence === "number");
|
|
@@ -13373,6 +13921,17 @@ var init_redact_tokens = __esm({
|
|
|
13373
13921
|
}
|
|
13374
13922
|
});
|
|
13375
13923
|
|
|
13924
|
+
// ../../scripts/ci/check-consensus-receipt-core.mjs
|
|
13925
|
+
var RECEIPT_MARKER_RE, UNAVAILABILITY_RE;
|
|
13926
|
+
var init_check_consensus_receipt_core = __esm({
|
|
13927
|
+
"../../scripts/ci/check-consensus-receipt-core.mjs"() {
|
|
13928
|
+
"use strict";
|
|
13929
|
+
init_methodology_composer();
|
|
13930
|
+
RECEIPT_MARKER_RE = /receipt id:\s*[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/iu;
|
|
13931
|
+
UNAVAILABILITY_RE = /consensus[^.\n]{0,80}(not available|unavailable|not permitted|could not be reached|no receipt_id)/iu;
|
|
13932
|
+
}
|
|
13933
|
+
});
|
|
13934
|
+
|
|
13376
13935
|
// ../../scripts/virtual-office/code-runner/task-helpers.mjs
|
|
13377
13936
|
function makeSafeProgress(log2) {
|
|
13378
13937
|
return async (client, id, patch) => {
|
|
@@ -13397,6 +13956,17 @@ ${String(run?.lastAgentMessage || "")}`;
|
|
|
13397
13956
|
const missing = found.filter((line) => !String(slicedBodyText || "").includes(line));
|
|
13398
13957
|
return missing.length ? ["", "### Consensus evidence (preserved past truncation)", "", ...missing.map((line) => redactSecrets(line))] : [];
|
|
13399
13958
|
}
|
|
13959
|
+
function consensusUnavailabilityLine(stakes) {
|
|
13960
|
+
const signal = String(stakes ?? "").replace(/\s+/gu, " ").trim().slice(0, 80) || "unspecified";
|
|
13961
|
+
return `Consensus judgment was not available in this headless session (no receipt_id) \u2014 automated declaration by the runner; stakes signal: ${signal}.`;
|
|
13962
|
+
}
|
|
13963
|
+
function withConsensusDeclaration(body, stakes) {
|
|
13964
|
+
const text = String(body ?? "");
|
|
13965
|
+
if (RECEIPT_MARKER_RE.test(text) || UNAVAILABILITY_RE.test(text)) return text;
|
|
13966
|
+
return `${text}
|
|
13967
|
+
|
|
13968
|
+
${consensusUnavailabilityLine(stakes)}`;
|
|
13969
|
+
}
|
|
13400
13970
|
function buildPrBody(task, run, files, { armAutoMerge = false } = {}) {
|
|
13401
13971
|
const governedStakes = matchGovernedStakes({ prompt: String(task.prompt || "") });
|
|
13402
13972
|
const slicedSections = [
|
|
@@ -13422,15 +13992,20 @@ function buildPrBody(task, run, files, { armAutoMerge = false } = {}) {
|
|
|
13422
13992
|
"",
|
|
13423
13993
|
// A budget/turn-capped run ends with no assistant text (summary = the bare
|
|
13424
13994
|
// subtype); its LAST message is the honest report the operator needs.
|
|
13425
|
-
...run.lastAgentMessage ? ["### Last agent message before the cap", "", redactSecrets(String(run.lastAgentMessage)).slice(0, 2e3), ""] : []
|
|
13995
|
+
...run.lastAgentMessage ? ["### Last agent message before the cap", "", redactSecrets(String(run.lastAgentMessage)).slice(0, 2e3), ""] : [],
|
|
13996
|
+
// Completion-gate failures salvaged against a budget/turn-truncated run
|
|
13997
|
+
// (D4, incident afc90342) — the gate output that would otherwise have
|
|
13998
|
+
// only lived in a terminal-failure message the runner never publishes.
|
|
13999
|
+
...run.gateFailureNote ? ["### Completion gate output (not yet passing)", "", redactSecrets(String(run.gateFailureNote)).slice(0, 2e3), ""] : []
|
|
13426
14000
|
];
|
|
13427
|
-
|
|
14001
|
+
const composed = [
|
|
13428
14002
|
...slicedSections,
|
|
13429
14003
|
// Receipt lines the slices dropped — the gate reads only this body.
|
|
13430
14004
|
...preservedReceiptLines(run, slicedSections.join("\n")),
|
|
13431
14005
|
"---",
|
|
13432
14006
|
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._"
|
|
13433
14007
|
].filter((l) => l !== "").join("\n");
|
|
14008
|
+
return governedStakes ? withConsensusDeclaration(composed, governedStakes) : composed;
|
|
13434
14009
|
}
|
|
13435
14010
|
async function mintRunnerGithubTokens({ client, taskId, log: log2, repo = null, requirePublish = false }) {
|
|
13436
14011
|
const publishToken = (await client.getInstallationToken({ required: requirePublish }))?.token ?? null;
|
|
@@ -13451,6 +14026,7 @@ var init_task_helpers = __esm({
|
|
|
13451
14026
|
"use strict";
|
|
13452
14027
|
init_redact_tokens();
|
|
13453
14028
|
init_methodology_composer();
|
|
14029
|
+
init_check_consensus_receipt_core();
|
|
13454
14030
|
RECEIPT_LINE_RE = /receipt id:\s*[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/giu;
|
|
13455
14031
|
}
|
|
13456
14032
|
});
|
|
@@ -15245,8 +15821,8 @@ var init_cancellation_probe = __esm({
|
|
|
15245
15821
|
});
|
|
15246
15822
|
|
|
15247
15823
|
// ../../scripts/virtual-office/code-runner/detached-economics-spool.mjs
|
|
15248
|
-
import { homedir as
|
|
15249
|
-
import { dirname as
|
|
15824
|
+
import { homedir as homedir13 } from "node:os";
|
|
15825
|
+
import { dirname as dirname13, join as join18 } from "node:path";
|
|
15250
15826
|
import { mkdir as mkdir4, readFile as readFile5, rename as rename2, writeFile as writeFile4 } from "node:fs/promises";
|
|
15251
15827
|
function withLock(operation) {
|
|
15252
15828
|
const result = serialized.then(operation, operation);
|
|
@@ -15264,7 +15840,7 @@ async function readEntries(file) {
|
|
|
15264
15840
|
}
|
|
15265
15841
|
}
|
|
15266
15842
|
async function writeEntries(file, entries) {
|
|
15267
|
-
await mkdir4(
|
|
15843
|
+
await mkdir4(dirname13(file), { recursive: true });
|
|
15268
15844
|
const temp = `${file}.${process.pid}.tmp`;
|
|
15269
15845
|
await writeFile4(temp, `${JSON.stringify(entries)}
|
|
15270
15846
|
`, "utf8");
|
|
@@ -15310,7 +15886,7 @@ var DEFAULT_FILE, serialized;
|
|
|
15310
15886
|
var init_detached_economics_spool = __esm({
|
|
15311
15887
|
"../../scripts/virtual-office/code-runner/detached-economics-spool.mjs"() {
|
|
15312
15888
|
"use strict";
|
|
15313
|
-
DEFAULT_FILE =
|
|
15889
|
+
DEFAULT_FILE = join18(homedir13(), ".vo", "detached-run-economics.json");
|
|
15314
15890
|
serialized = Promise.resolve();
|
|
15315
15891
|
}
|
|
15316
15892
|
});
|
|
@@ -15688,6 +16264,19 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
|
|
|
15688
16264
|
allowMissingKnowledgeContext: process.env.VO_CODE_RUNNER_ALLOW_MISSING_KNOWLEDGE_CONTEXT === "1",
|
|
15689
16265
|
attachmentManifestMarkdown: attachmentBundle.manifestMarkdown
|
|
15690
16266
|
}) });
|
|
16267
|
+
await runPreparedJobShadow({ client, task, agent: sel.agent, env: process.env, log, local: {
|
|
16268
|
+
// ADR-004 § 11.1b SHADOW: default OFF; return value deliberately unread — slice C owns consumption
|
|
16269
|
+
prompt: effortPrompt,
|
|
16270
|
+
dispatchMode,
|
|
16271
|
+
tier,
|
|
16272
|
+
model,
|
|
16273
|
+
permissionMode: effectivePermissionMode,
|
|
16274
|
+
maxTurns: effectiveMaxTurns,
|
|
16275
|
+
effort: effectiveEffort,
|
|
16276
|
+
maxBudgetUsd: effectiveMaxBudgetUsd,
|
|
16277
|
+
methodology,
|
|
16278
|
+
attachmentManifestMarkdown: attachmentBundle.manifestMarkdown
|
|
16279
|
+
} });
|
|
15691
16280
|
assertRunnerGovernors({
|
|
15692
16281
|
agent: sel.agent,
|
|
15693
16282
|
// Only persisted operator caps are hard contracts. Router/global values
|
|
@@ -15803,7 +16392,7 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
|
|
|
15803
16392
|
}
|
|
15804
16393
|
if (await taskWasCancelled({ client, id, run, safeProgress, log })) return;
|
|
15805
16394
|
if (await gateTestGenTaskOrFail({ client, id, task, files, worktreeDir: wt.worktreeDir, log })) return;
|
|
15806
|
-
if (await enforceCompletionGateOrFail({ client, id, task, worktreeDir: wt.worktreeDir, log })) return;
|
|
16395
|
+
if (await enforceCompletionGateOrFail({ client, id, task, worktreeDir: wt.worktreeDir, run, truncated: partial, log })) return;
|
|
15807
16396
|
const publicationTarget = await resolvePublicationTarget({ task, continuationRestore, worktreeDir: wt.worktreeDir, githubToken, allowAmbientGithubFallback: cfg.allowAmbientGithub });
|
|
15808
16397
|
const localBranch = await resolveOrCreateBranchAsync(wt.worktreeDir, "vo/code-task");
|
|
15809
16398
|
const publicationBranch = publicationTarget.targetBranch || localBranch;
|
|
@@ -15896,6 +16485,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
15896
16485
|
let reconcileStale = true;
|
|
15897
16486
|
let stopping = false;
|
|
15898
16487
|
let active = 0;
|
|
16488
|
+
const activeTaskIds = /* @__PURE__ */ new Set();
|
|
15899
16489
|
const stop = (sig) => {
|
|
15900
16490
|
if (stopping) return;
|
|
15901
16491
|
stopping = true;
|
|
@@ -15910,6 +16500,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
15910
16500
|
runnerInstanceId,
|
|
15911
16501
|
requestStop: () => stop("web-control"),
|
|
15912
16502
|
getActiveCount: () => active,
|
|
16503
|
+
getActiveTaskIds: () => [...activeTaskIds],
|
|
15913
16504
|
isRunning: () => !stopping,
|
|
15914
16505
|
startedAt,
|
|
15915
16506
|
log,
|
|
@@ -15950,7 +16541,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
15950
16541
|
const agentAvailability = makeAgentAvailabilityProvider({ onError: (e) => log(`agent probe failed: ${e.message}`) });
|
|
15951
16542
|
await agentAvailability.ready();
|
|
15952
16543
|
const accountUsage = makeAccountUsageProvider();
|
|
15953
|
-
const loopTick = makeLoopTicks({ client, cfg, env: env2, log, getActive: () => active, runnerInstanceId, capacityController, localModelController: createLocalModelRemoteController({ env: env2, log }), getAgentAvailability: () => agentAvailability.get(), getAccountUsage: () => accountUsage.get() });
|
|
16544
|
+
const loopTick = makeLoopTicks({ client, cfg, env: env2, log, getActive: () => active, runnerInstanceId, capacityController, localModelController: createLocalModelRemoteController({ env: env2, log }), preparedJobController: createPreparedJobRemoteController({ log }), getAgentAvailability: () => agentAvailability.get(), getAccountUsage: () => accountUsage.get() });
|
|
15954
16545
|
const backoff = makeReconnectBackoff({ baseMs: cfg.pollSec * 1e3, log });
|
|
15955
16546
|
let detachedFlushRunning = false;
|
|
15956
16547
|
while (!stopping) {
|
|
@@ -16000,6 +16591,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
16000
16591
|
}
|
|
16001
16592
|
log(`claimed task ${task.code_task_id} (${task.repo})`);
|
|
16002
16593
|
active += 1;
|
|
16594
|
+
activeTaskIds.add(task.code_task_id);
|
|
16003
16595
|
const runTask = task.kind === "inference" ? processInferenceTask(client, task, cfg, { safeProgress, runnerStagePatch, log }) : processOneTask(client, task, cfg, runnerInstanceId, { availableAgents: claimAgents.availableAgents, accountUsage: accountUsage.get() });
|
|
16004
16596
|
const done = runTask.catch(async (error) => {
|
|
16005
16597
|
log(`task ${task.code_task_id} unhandled runner error: ${error.message}`);
|
|
@@ -16019,6 +16611,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
16019
16611
|
});
|
|
16020
16612
|
}).finally(() => {
|
|
16021
16613
|
active -= 1;
|
|
16614
|
+
activeTaskIds.delete(task.code_task_id);
|
|
16022
16615
|
});
|
|
16023
16616
|
if (once2) {
|
|
16024
16617
|
await done;
|
|
@@ -16052,6 +16645,7 @@ var init_code_runner_daemon = __esm({
|
|
|
16052
16645
|
init_runner_capacity();
|
|
16053
16646
|
init_agent_availability();
|
|
16054
16647
|
init_local_model_remote_config();
|
|
16648
|
+
init_prepared_job_remote_config();
|
|
16055
16649
|
init_account_usage2();
|
|
16056
16650
|
init_pr_watcher();
|
|
16057
16651
|
init_existing_pr_target();
|
|
@@ -16061,6 +16655,7 @@ var init_code_runner_daemon = __esm({
|
|
|
16061
16655
|
init_claim_scoping_log();
|
|
16062
16656
|
init_reconnect_backoff();
|
|
16063
16657
|
init_task_helpers();
|
|
16658
|
+
init_prepared_job_shadow();
|
|
16064
16659
|
init_agent_process_env();
|
|
16065
16660
|
init_sandbox_config();
|
|
16066
16661
|
init_inference_task_runner();
|