@algosuite/vo-mcp 0.2.0-beta.16 → 0.2.0-beta.18

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.
@@ -424,7 +424,7 @@ async function runProcess(command, args = [], options = {}) {
424
424
  const killGraceMs = options.killGraceMs ?? DEFAULT_KILL_GRACE_MS;
425
425
  const forceKillTimeoutMs = options.forceKillTimeoutMs ?? DEFAULT_FORCE_KILL_TIMEOUT_MS;
426
426
  const spawnImpl = options.spawnImpl || spawn;
427
- const killProcessTree = options.killProcessTree || killProcessTreeDefault;
427
+ const killProcessTree2 = options.killProcessTree || killProcessTreeDefault;
428
428
  const spawnOptions = {
429
429
  cwd: options.cwd,
430
430
  env: options.env,
@@ -462,7 +462,7 @@ async function runProcess(command, args = [], options = {}) {
462
462
  forceKillTimeout.unref?.();
463
463
  void (async () => {
464
464
  try {
465
- await killProcessTree(child.pid, { timeoutMs: forceKillTimeoutMs });
465
+ await killProcessTree2(child.pid, { timeoutMs: forceKillTimeoutMs });
466
466
  } catch (error) {
467
467
  finish({ status: null, error });
468
468
  }
@@ -2142,11 +2142,11 @@ function createControlPlaneClient({
2142
2142
  throw new Error("VO_CONTROL_PLANE_URL is required for the code-runner daemon");
2143
2143
  }
2144
2144
  const root = resolvedBaseUrl.replace(/\/+$/, "");
2145
- async function req(method, path17, body, { timeoutMs } = {}) {
2145
+ async function req(method, path18, body, { timeoutMs } = {}) {
2146
2146
  const bearer = await resolveBearer(env2);
2147
2147
  const controller = timeoutMs ? new AbortController() : null;
2148
2148
  let timeoutId;
2149
- const request = Promise.resolve(fetchImpl(`${root}${path17}`, {
2149
+ const request = Promise.resolve(fetchImpl(`${root}${path18}`, {
2150
2150
  method,
2151
2151
  headers: {
2152
2152
  "content-type": "application/json",
@@ -2159,7 +2159,7 @@ function createControlPlaneClient({
2159
2159
  const timeout = new Promise((_, reject) => {
2160
2160
  timeoutId = setTimeout(() => {
2161
2161
  controller.abort();
2162
- reject(new Error(`control-plane ${path17} timed out after ${timeoutMs}ms`));
2162
+ reject(new Error(`control-plane ${path18} timed out after ${timeoutMs}ms`));
2163
2163
  }, timeoutMs);
2164
2164
  });
2165
2165
  try {
@@ -2278,8 +2278,8 @@ function createControlPlaneClient({
2278
2278
  return json ? json.task : null;
2279
2279
  },
2280
2280
  async downloadTaskAttachment(taskId, attachmentId) {
2281
- const path17 = `/api/v1/code-task/${encodeURIComponent(taskId)}/attachment/${encodeURIComponent(attachmentId)}`;
2282
- const res = await req("GET", path17);
2281
+ const path18 = `/api/v1/code-task/${encodeURIComponent(taskId)}/attachment/${encodeURIComponent(attachmentId)}`;
2282
+ const res = await req("GET", path18);
2283
2283
  if (res.status === 401) cachedFirebaseToken = null;
2284
2284
  if (!res.ok) throw new Error(`attachment download failed: HTTP ${res.status}`);
2285
2285
  return Buffer.from(await res.arrayBuffer());
@@ -2792,8 +2792,8 @@ function buildDockerArgs({
2792
2792
  image = DEFAULT_SANDBOX_IMAGE,
2793
2793
  agentBin = "claude",
2794
2794
  agentArgs = [],
2795
- passEnv = ["ANTHROPIC_API_KEY"],
2796
- network = "bridge",
2795
+ passEnv = [],
2796
+ network = "none",
2797
2797
  memory = "4g",
2798
2798
  cpus = "2",
2799
2799
  pids = "512",
@@ -2950,6 +2950,302 @@ var init_terminal_process_cleanup = __esm({
2950
2950
  }
2951
2951
  });
2952
2952
 
2953
+ // ../../scripts/virtual-office/code-runner/orphan-agent-reaper.mjs
2954
+ import { spawnSync as spawnSync5 } from "node:child_process";
2955
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
2956
+ import os from "node:os";
2957
+ import path10 from "node:path";
2958
+ function registryRoot(tmp = os.tmpdir()) {
2959
+ return path10.join(tmp, REGISTRY_ROOT_NAME);
2960
+ }
2961
+ function instanceDir(root, instanceId) {
2962
+ return path10.join(root, String(instanceId).replace(/[^A-Za-z0-9_-]/g, ""));
2963
+ }
2964
+ function registerDaemonInstance({
2965
+ root = registryRoot(),
2966
+ instanceId,
2967
+ daemonPid = process.pid,
2968
+ daemonStartedAtMs = Date.now()
2969
+ } = {}) {
2970
+ if (!instanceId) return null;
2971
+ const dir = instanceDir(root, instanceId);
2972
+ mkdirSync2(dir, { recursive: true });
2973
+ const file = path10.join(dir, DAEMON_RECORD);
2974
+ writeFileSync2(file, JSON.stringify({ daemonPid, daemonStartedAtMs, instanceId }), {
2975
+ encoding: "utf8",
2976
+ mode: 384
2977
+ });
2978
+ return file;
2979
+ }
2980
+ function recordAgentPid({
2981
+ root = registryRoot(),
2982
+ instanceId = process.env.VO_RUNNER_INSTANCE_ID,
2983
+ pid,
2984
+ agentId = "",
2985
+ startedAtMs = Date.now()
2986
+ } = {}) {
2987
+ if (!instanceId || !Number.isInteger(pid) || pid <= 0) return false;
2988
+ try {
2989
+ const dir = instanceDir(root, instanceId);
2990
+ mkdirSync2(dir, { recursive: true });
2991
+ writeFileSync2(
2992
+ path10.join(dir, `${pid}.json`),
2993
+ JSON.stringify({ pid, agentId, startedAtMs, instanceId }),
2994
+ { encoding: "utf8", mode: 384 }
2995
+ );
2996
+ return true;
2997
+ } catch {
2998
+ return false;
2999
+ }
3000
+ }
3001
+ function unrecordAgentPid({
3002
+ root = registryRoot(),
3003
+ instanceId = process.env.VO_RUNNER_INSTANCE_ID,
3004
+ pid
3005
+ } = {}) {
3006
+ if (!instanceId || !Number.isInteger(pid)) return false;
3007
+ try {
3008
+ rmSync2(path10.join(instanceDir(root, instanceId), `${pid}.json`), { force: true });
3009
+ return true;
3010
+ } catch {
3011
+ return false;
3012
+ }
3013
+ }
3014
+ function bootstrapOrphanReaper({ instanceId, log: log3 = () => {
3015
+ } } = {}) {
3016
+ if (!instanceId) return { killed: 0, prunedDirs: 0 };
3017
+ process.env.VO_RUNNER_INSTANCE_ID = instanceId;
3018
+ try {
3019
+ registerDaemonInstance({ instanceId });
3020
+ } catch {
3021
+ }
3022
+ return reapOrphanedAgents({ currentInstanceId: instanceId, log: log3 });
3023
+ }
3024
+ function readRegistry({ root = registryRoot(), currentInstanceId } = {}) {
3025
+ const instances = [];
3026
+ if (!existsSync3(root)) return instances;
3027
+ let dirents;
3028
+ try {
3029
+ dirents = readdirSync(root, { withFileTypes: true });
3030
+ } catch {
3031
+ return instances;
3032
+ }
3033
+ for (const dirent of dirents) {
3034
+ if (!dirent.isDirectory()) continue;
3035
+ if (currentInstanceId && dirent.name === instanceDirName(currentInstanceId)) continue;
3036
+ const dir = path10.join(root, dirent.name);
3037
+ let daemon = null;
3038
+ const agents = [];
3039
+ let files;
3040
+ try {
3041
+ files = readdirSync(dir);
3042
+ } catch {
3043
+ continue;
3044
+ }
3045
+ for (const name of files) {
3046
+ let parsed;
3047
+ try {
3048
+ parsed = JSON.parse(readFileSync2(path10.join(dir, name), "utf8"));
3049
+ } catch {
3050
+ continue;
3051
+ }
3052
+ if (name === DAEMON_RECORD) {
3053
+ if (Number.isInteger(parsed?.daemonPid)) {
3054
+ daemon = { pid: parsed.daemonPid, startedAtMs: Number(parsed.daemonStartedAtMs) || 0 };
3055
+ }
3056
+ } else if (Number.isInteger(parsed?.pid)) {
3057
+ agents.push({ pid: parsed.pid, agentId: String(parsed.agentId || ""), startedAtMs: Number(parsed.startedAtMs) || 0 });
3058
+ }
3059
+ }
3060
+ instances.push({ instanceId: dirent.name, dir, daemon, agents });
3061
+ }
3062
+ return instances;
3063
+ }
3064
+ function instanceDirName(instanceId) {
3065
+ return String(instanceId).replace(/[^A-Za-z0-9_-]/g, "");
3066
+ }
3067
+ function creationMatches(live, recordedStartedAtMs, toleranceMs) {
3068
+ if (!live || !Number.isFinite(live.creationMs)) return false;
3069
+ if (!Number.isFinite(recordedStartedAtMs) || recordedStartedAtMs <= 0) return false;
3070
+ return Math.abs(live.creationMs - recordedStartedAtMs) <= toleranceMs;
3071
+ }
3072
+ function selectOrphanKills({ instances = [], liveProcesses = /* @__PURE__ */ new Map(), toleranceMs = CREATION_MATCH_TOLERANCE_MS } = {}) {
3073
+ const kills = [];
3074
+ const pruneDirs = [];
3075
+ for (const instance of instances) {
3076
+ if (!instance.daemon) {
3077
+ if (instance.dir) pruneDirs.push(instance.dir);
3078
+ continue;
3079
+ }
3080
+ const daemonLive = liveProcesses.has(instance.daemon.pid) && creationMatches(liveProcesses.get(instance.daemon.pid), instance.daemon.startedAtMs, toleranceMs);
3081
+ if (daemonLive) continue;
3082
+ for (const agent of instance.agents) {
3083
+ const live = liveProcesses.get(agent.pid);
3084
+ if (live && creationMatches(live, agent.startedAtMs, toleranceMs)) {
3085
+ kills.push({ pid: agent.pid, agentId: agent.agentId, instanceId: instance.instanceId });
3086
+ }
3087
+ }
3088
+ if (instance.dir) pruneDirs.push(instance.dir);
3089
+ }
3090
+ return { kills, pruneDirs };
3091
+ }
3092
+ function listProcessCreationTimes({ platform = process.platform, spawn: spawn5 = spawnSync5 } = {}) {
3093
+ const map = /* @__PURE__ */ new Map();
3094
+ if (platform === "win32") {
3095
+ const ps = "Get-CimInstance Win32_Process | ForEach-Object { '{0} {1}' -f $_.ProcessId, (([DateTimeOffset]$_.CreationDate.ToUniversalTime()).ToUnixTimeMilliseconds()) }";
3096
+ const result2 = spawn5("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], {
3097
+ windowsHide: true,
3098
+ encoding: "utf8",
3099
+ timeout: 2e4,
3100
+ maxBuffer: 32 * 1024 * 1024
3101
+ });
3102
+ if (result2.error || result2.status !== 0 || typeof result2.stdout !== "string") return map;
3103
+ for (const line of result2.stdout.split(/\r?\n/)) {
3104
+ const m = line.trim().match(/^(\d+)\s+(-?\d+)$/);
3105
+ if (m) map.set(Number(m[1]), { creationMs: Number(m[2]) });
3106
+ }
3107
+ return map;
3108
+ }
3109
+ const result = spawn5("ps", ["-eo", "pid=,lstart="], { encoding: "utf8", timeout: 2e4, maxBuffer: 32 * 1024 * 1024 });
3110
+ if (result.error || result.status !== 0 || typeof result.stdout !== "string") return map;
3111
+ for (const line of result.stdout.split(/\r?\n/)) {
3112
+ const parsed = parsePosixPsLine(line);
3113
+ if (parsed) map.set(parsed.pid, { creationMs: parsed.creationMs });
3114
+ }
3115
+ return map;
3116
+ }
3117
+ function parsePosixPsLine(line) {
3118
+ const trimmed = String(line ?? "").trim();
3119
+ const sp = trimmed.indexOf(" ");
3120
+ if (sp <= 0) return null;
3121
+ const pid = Number(trimmed.slice(0, sp));
3122
+ const when = Date.parse(trimmed.slice(sp + 1).trim());
3123
+ if (!Number.isInteger(pid) || pid <= 0 || !Number.isFinite(when)) return null;
3124
+ return { pid, creationMs: when };
3125
+ }
3126
+ function killProcessTree(pid, { platform = process.platform, spawn: spawn5 = spawnSync5 } = {}) {
3127
+ if (!Number.isInteger(pid) || pid <= 0) return false;
3128
+ if (platform === "win32") {
3129
+ const r = spawn5("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore", timeout: 15e3 });
3130
+ return !r.error && r.status === 0;
3131
+ }
3132
+ try {
3133
+ process.kill(-pid, "SIGKILL");
3134
+ return true;
3135
+ } catch {
3136
+ try {
3137
+ process.kill(pid, "SIGKILL");
3138
+ return true;
3139
+ } catch {
3140
+ return false;
3141
+ }
3142
+ }
3143
+ }
3144
+ function reapOrphanedAgents({
3145
+ root = registryRoot(),
3146
+ currentInstanceId = process.env.VO_RUNNER_INSTANCE_ID,
3147
+ toleranceMs = CREATION_MATCH_TOLERANCE_MS,
3148
+ listProcesses = listProcessCreationTimes,
3149
+ killTree = killProcessTree,
3150
+ log: log3 = () => {
3151
+ }
3152
+ } = {}) {
3153
+ try {
3154
+ const instances = readRegistry({ root, currentInstanceId });
3155
+ if (instances.length === 0) return { killed: 0, prunedDirs: 0 };
3156
+ const liveProcesses = listProcesses();
3157
+ const { kills, pruneDirs } = selectOrphanKills({ instances, liveProcesses, toleranceMs });
3158
+ let killed = 0;
3159
+ for (const kill of kills) {
3160
+ if (killTree(kill.pid)) {
3161
+ killed += 1;
3162
+ log3(`reaped orphaned agent pid ${kill.pid}${kill.agentId ? ` (${kill.agentId})` : ""} from dead instance ${kill.instanceId}`);
3163
+ }
3164
+ }
3165
+ let prunedDirs = 0;
3166
+ for (const dir of pruneDirs) {
3167
+ try {
3168
+ rmSync2(dir, { recursive: true, force: true });
3169
+ prunedDirs += 1;
3170
+ } catch {
3171
+ }
3172
+ }
3173
+ if (killed > 0 || prunedDirs > 0) log3(`orphan reap: killed ${killed} agent tree(s), pruned ${prunedDirs} dead instance record(s)`);
3174
+ return { killed, prunedDirs };
3175
+ } catch (error) {
3176
+ log3(`orphan reap skipped: ${error instanceof Error ? error.message : String(error)}`);
3177
+ return { killed: 0, prunedDirs: 0 };
3178
+ }
3179
+ }
3180
+ var REGISTRY_ROOT_NAME, DAEMON_RECORD, CREATION_MATCH_TOLERANCE_MS;
3181
+ var init_orphan_agent_reaper = __esm({
3182
+ "../../scripts/virtual-office/code-runner/orphan-agent-reaper.mjs"() {
3183
+ "use strict";
3184
+ REGISTRY_ROOT_NAME = "algohq-runner-agent-pids";
3185
+ DAEMON_RECORD = "daemon.json";
3186
+ CREATION_MATCH_TOLERANCE_MS = 3e4;
3187
+ }
3188
+ });
3189
+
3190
+ // ../../scripts/virtual-office/code-runner/cli-version-floor.mjs
3191
+ function parseCliVersion(output) {
3192
+ const match = /\b(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?\b/.exec(String(output ?? ""));
3193
+ return match ? `${match[1]}.${match[2]}.${match[3]}` : null;
3194
+ }
3195
+ function compareSemver(a, b) {
3196
+ const pa = a.split(".").map(Number);
3197
+ const pb = b.split(".").map(Number);
3198
+ for (let i = 0; i < 3; i += 1) {
3199
+ if (pa[i] !== pb[i]) return pa[i] < pb[i] ? -1 : 1;
3200
+ }
3201
+ return 0;
3202
+ }
3203
+ function checkCliVersionFloor(versionOutput, { floor = MIN_CLAUDE_CLI_VERSION } = {}) {
3204
+ const version = parseCliVersion(versionOutput);
3205
+ if (!version) {
3206
+ const seen = String(versionOutput ?? "").trim().slice(0, 120) || "<empty>";
3207
+ return {
3208
+ ok: false,
3209
+ version: null,
3210
+ floor,
3211
+ message: `could not parse a semver from \`claude --version\` output ("${seen}") \u2014 cannot prove the CLI meets the ${floor} security floor. ${SECURITY_RATIONALE}`
3212
+ };
3213
+ }
3214
+ if (compareSemver(version, floor) < 0) {
3215
+ return {
3216
+ ok: false,
3217
+ version,
3218
+ floor,
3219
+ message: `claude CLI ${version} is BELOW the minimum security floor ${floor}. ` + SECURITY_RATIONALE
3220
+ };
3221
+ }
3222
+ return {
3223
+ ok: true,
3224
+ version,
3225
+ floor,
3226
+ message: `claude CLI ${version} meets the minimum security floor ${floor}`
3227
+ };
3228
+ }
3229
+ function applyCliVersionFloor({ versionOutput, env: env2 = process.env, log: log3 = console.error } = {}) {
3230
+ const check = checkCliVersionFloor(versionOutput);
3231
+ if (check.ok) return { refused: false, check, message: check.message };
3232
+ const enforce = String(env2?.VO_CLI_FLOOR_ENFORCE ?? "") === "1";
3233
+ const message = `[cli-version-floor] ${enforce ? "REFUSING (VO_CLI_FLOOR_ENFORCE=1)" : "WARNING (warn-only)"}: ` + check.message;
3234
+ try {
3235
+ log3(message);
3236
+ } catch {
3237
+ }
3238
+ return { refused: enforce, check, message };
3239
+ }
3240
+ var MIN_CLAUDE_CLI_VERSION, SECURITY_RATIONALE;
3241
+ var init_cli_version_floor = __esm({
3242
+ "../../scripts/virtual-office/code-runner/cli-version-floor.mjs"() {
3243
+ "use strict";
3244
+ MIN_CLAUDE_CLI_VERSION = "2.1.216";
3245
+ SECURITY_RATIONALE = "Claude Code 2.1.211/2.1.213 fixed a PreToolUse-hook bypass on unsandboxed Bash (our destructive-fs/git/cloud tripwires DO NOT FIRE on older CLIs) and worktree-subagents mutating the main checkout. Update: npm install -g @anthropic-ai/claude-code (or the native installer).";
3246
+ }
3247
+ });
3248
+
2953
3249
  // ../../scripts/virtual-office/code-runner/claude-runner.mjs
2954
3250
  import { spawn as spawn2 } from "node:child_process";
2955
3251
  function extractText(content) {
@@ -3040,6 +3336,7 @@ function runAgentTask({
3040
3336
  stdio: ["pipe", "pipe", "pipe"],
3041
3337
  ...spawnOpts
3042
3338
  });
3339
+ recordAgentPid({ pid: child.pid, agentId: spawnBin });
3043
3340
  try {
3044
3341
  child.stdin.write(String(prompt));
3045
3342
  child.stdin.end();
@@ -3155,6 +3452,7 @@ function runAgentTask({
3155
3452
  exitDrainTimer = setTimeout(() => finalizeChild({ code, signal }), exitDrainGraceMs);
3156
3453
  });
3157
3454
  child.on("close", (code, signal) => {
3455
+ unrecordAgentPid({ pid: child.pid });
3158
3456
  finalizeChild({ code, signal });
3159
3457
  });
3160
3458
  });
@@ -3169,6 +3467,8 @@ var init_claude_runner = __esm({
3169
3467
  init_claude_args();
3170
3468
  init_windows_claude_launch();
3171
3469
  init_terminal_process_cleanup();
3470
+ init_orphan_agent_reaper();
3471
+ init_cli_version_floor();
3172
3472
  ClaudeRunner = class {
3173
3473
  get binary() {
3174
3474
  return "claude";
@@ -3205,7 +3505,7 @@ var init_claude_runner = __esm({
3205
3505
  */
3206
3506
  async checkAuth() {
3207
3507
  try {
3208
- const probe = spawnClaudeSync(["--version"], { timeout: 3e3, stdio: "ignore" });
3508
+ const probe = spawnClaudeSync(["--version"], { timeout: 3e3, encoding: "utf8" });
3209
3509
  if (probe.error) {
3210
3510
  return {
3211
3511
  installed: false,
@@ -3216,6 +3516,8 @@ var init_claude_runner = __esm({
3216
3516
  if (probe.status !== 0) {
3217
3517
  return { installed: true, authenticated: false, message: "claude binary exists but --version failed (auth unclear)" };
3218
3518
  }
3519
+ const floorGate = applyCliVersionFloor({ versionOutput: probe.stdout, env: process.env });
3520
+ if (floorGate.refused) return { installed: true, authenticated: false, message: floorGate.message };
3219
3521
  const loggedIn = probeClaudeLoginState();
3220
3522
  if (loggedIn === false) {
3221
3523
  return {
@@ -3314,17 +3616,8 @@ var init_agent_key_store = __esm({
3314
3616
  });
3315
3617
 
3316
3618
  // ../../scripts/virtual-office/code-runner/codex-runner.mjs
3317
- var codex_runner_exports = {};
3318
- __export(codex_runner_exports, {
3319
- CODEX_PREFER_LOGIN_ENV: () => CODEX_PREFER_LOGIN_ENV,
3320
- CodexRunner: () => CodexRunner,
3321
- buildCodexArgs: () => buildCodexArgs,
3322
- codexRunner: () => codexRunner,
3323
- parseCodexEvent: () => parseCodexEvent,
3324
- resolveCodexBinary: () => resolveCodexBinary
3325
- });
3326
- import { spawnSync as spawnSync5 } from "node:child_process";
3327
- import { existsSync as existsSync3 } from "node:fs";
3619
+ import { spawnSync as spawnSync6 } from "node:child_process";
3620
+ import { existsSync as existsSync4 } from "node:fs";
3328
3621
  import { win32 } from "node:path";
3329
3622
  function isTruthyFlag2(value) {
3330
3623
  return ["1", "true", "yes", "on"].includes(String(value ?? "").trim().toLowerCase());
@@ -3332,7 +3625,7 @@ function isTruthyFlag2(value) {
3332
3625
  function resolveCodexBinary({
3333
3626
  env: env2 = process.env,
3334
3627
  platform = process.platform,
3335
- exists = existsSync3
3628
+ exists = existsSync4
3336
3629
  } = {}) {
3337
3630
  if (platform !== "win32") return "codex";
3338
3631
  const appData = String(env2.APPDATA || "").trim();
@@ -3367,7 +3660,7 @@ function resolveCodexBinary({
3367
3660
  return "codex";
3368
3661
  }
3369
3662
  function buildCodexArgs({ model, effort } = {}) {
3370
- const args = ["exec", "--json", "-c", 'approval_policy="never"', "--sandbox", "danger-full-access"];
3663
+ const args = ["exec", "--json", "-c", 'approval_policy="never"', "--sandbox", "workspace-write"];
3371
3664
  if (model) {
3372
3665
  args.push("--model", String(model));
3373
3666
  }
@@ -3422,7 +3715,7 @@ var init_codex_runner = __esm({
3422
3715
  CODEX_PREFER_LOGIN_ENV = "VO_RUNNER_CODEX_PREFER_LOGIN";
3423
3716
  LEGACY_PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
3424
3717
  CodexRunner = class {
3425
- constructor({ spawn: spawn5 = spawnSync5, resolveBinary = resolveCodexBinary, env: env2 = process.env } = {}) {
3718
+ constructor({ spawn: spawn5 = spawnSync6, resolveBinary = resolveCodexBinary, env: env2 = process.env } = {}) {
3426
3719
  this.spawn = spawn5;
3427
3720
  this.resolveBinary = resolveBinary;
3428
3721
  this.env = env2;
@@ -3512,7 +3805,7 @@ ${login.stderr || ""}`.trim();
3512
3805
  });
3513
3806
 
3514
3807
  // ../../scripts/virtual-office/code-runner/cursor-runner.mjs
3515
- import { spawnSync as spawnSync6 } from "node:child_process";
3808
+ import { spawnSync as spawnSync7 } from "node:child_process";
3516
3809
  function buildCursorArgs({ model, prompt } = {}) {
3517
3810
  const args = ["-p", "--output-format", "stream-json", "--force"];
3518
3811
  if (model) {
@@ -3591,7 +3884,7 @@ var init_cursor_runner = __esm({
3591
3884
  /** Best-effort: is `cursor-agent` on PATH? Never throws. */
3592
3885
  async checkAuth() {
3593
3886
  try {
3594
- const { status, error } = spawnSync6("cursor-agent", ["--version"], {
3887
+ const { status, error } = spawnSync7("cursor-agent", ["--version"], {
3595
3888
  shell: process.platform === "win32",
3596
3889
  windowsHide: true,
3597
3890
  timeout: 3e3,
@@ -3617,45 +3910,6 @@ var init_cursor_runner = __esm({
3617
3910
  }
3618
3911
  });
3619
3912
 
3620
- // ../../scripts/virtual-office/code-runner/meta-model-catalog.mjs
3621
- function normalizeMetaEffort(value) {
3622
- const normalized = String(value || "").trim().toLowerCase();
3623
- if (["low", "medium", "high", "xhigh"].includes(normalized)) return normalized;
3624
- if (normalized === "max") return "xhigh";
3625
- return null;
3626
- }
3627
- function resolveMetaModelForTier() {
3628
- return META_DEFAULT_MODEL;
3629
- }
3630
- function resolveMetaEffortForTier(tier = "mid") {
3631
- return TIER_EFFORT[tier] || TIER_EFFORT.mid;
3632
- }
3633
- function resolveMetaEffortForRung(rung = "R3") {
3634
- return RUNG_EFFORT[rung] || RUNG_EFFORT.R3;
3635
- }
3636
- var META_DEFAULT_MODEL, META_API_BASE_URL, META_CONTEXT_WINDOW, META_MAX_OUTPUT_TOKENS, TIER_EFFORT, RUNG_EFFORT;
3637
- var init_meta_model_catalog = __esm({
3638
- "../../scripts/virtual-office/code-runner/meta-model-catalog.mjs"() {
3639
- "use strict";
3640
- META_DEFAULT_MODEL = "muse-spark-1.1";
3641
- META_API_BASE_URL = "https://api.meta.ai/v1";
3642
- META_CONTEXT_WINDOW = 1048576;
3643
- META_MAX_OUTPUT_TOKENS = 131072;
3644
- TIER_EFFORT = Object.freeze({
3645
- cheap: "low",
3646
- mid: "medium",
3647
- best: "xhigh"
3648
- });
3649
- RUNG_EFFORT = Object.freeze({
3650
- R1: "low",
3651
- R2: "medium",
3652
- R3: "medium",
3653
- R4: "high",
3654
- R5: "xhigh"
3655
- });
3656
- }
3657
- });
3658
-
3659
3913
  // ../../scripts/virtual-office/code-runner/meta-runner.mjs
3660
3914
  function applyMetaAuthEnv(baseEnv = process.env) {
3661
3915
  const out = withAgentKey("meta", baseEnv);
@@ -3665,44 +3919,17 @@ function applyMetaAuthEnv(baseEnv = process.env) {
3665
3919
  return out;
3666
3920
  }
3667
3921
  function buildMetaArgs(opts = {}) {
3668
- const model = String(opts.model || "").trim() || META_DEFAULT_MODEL;
3669
- const args = [
3670
- "exec",
3671
- "--json",
3672
- "-c",
3673
- 'approval_policy="never"',
3674
- "--sandbox",
3675
- "danger-full-access",
3676
- "-c",
3677
- `model_providers.${PROVIDER_SLUG}.name="Meta Muse Spark"`,
3678
- "-c",
3679
- `model_providers.${PROVIDER_SLUG}.base_url="${META_API_BASE_URL}"`,
3680
- "-c",
3681
- `model_providers.${PROVIDER_SLUG}.env_key="${META_API_KEY_ENV}"`,
3682
- "-c",
3683
- `model_providers.${PROVIDER_SLUG}.wire_api="responses"`,
3684
- "-c",
3685
- `model_provider="${PROVIDER_SLUG}"`,
3686
- "-c",
3687
- `model_context_window=${META_CONTEXT_WINDOW}`,
3688
- "-c",
3689
- `model_max_output_tokens=${META_MAX_OUTPUT_TOKENS}`,
3690
- "--model",
3691
- model
3692
- ];
3693
- const effort = normalizeMetaEffort(opts.effort);
3694
- if (effort) args.push("-c", `model_reasoning_effort="${effort}"`);
3695
- args.push("-");
3696
- return args;
3922
+ void opts;
3923
+ throw new Error(
3924
+ "Muse Spark full-repository coding is disabled by the AlgoSuite Model Firewall policy. Use Muse only as a restricted reviewer through a sanitized task capsule."
3925
+ );
3697
3926
  }
3698
- var PROVIDER_SLUG, META_API_KEY_ENV, META_API_KEY_ALIAS, MetaRunner, metaRunner;
3927
+ var META_API_KEY_ENV, META_API_KEY_ALIAS, MetaRunner, metaRunner;
3699
3928
  var init_meta_runner = __esm({
3700
3929
  "../../scripts/virtual-office/code-runner/meta-runner.mjs"() {
3701
3930
  "use strict";
3702
3931
  init_codex_runner();
3703
3932
  init_agent_key_store();
3704
- init_meta_model_catalog();
3705
- PROVIDER_SLUG = "meta";
3706
3933
  META_API_KEY_ENV = "MODEL_API_KEY";
3707
3934
  META_API_KEY_ALIAS = "META_API";
3708
3935
  MetaRunner = class {
@@ -3731,21 +3958,10 @@ var init_meta_runner = __esm({
3731
3958
  return `meta muse-spark key=${hasKey ? "set" : "MISSING"} transport=codex`;
3732
3959
  }
3733
3960
  async checkAuth() {
3734
- const { CodexRunner: CodexRunner2 } = await Promise.resolve().then(() => (init_codex_runner(), codex_runner_exports));
3735
- const codex = await new CodexRunner2().checkAuth();
3736
- if (!codex.installed) {
3737
- return {
3738
- installed: false,
3739
- authenticated: false,
3740
- message: `codex transport not on PATH (npm i -g @openai/codex): ${codex.message}`
3741
- };
3742
- }
3743
- const authEnv = applyMetaAuthEnv(process.env);
3744
- const hasKey = Boolean(String(authEnv[META_API_KEY_ENV] || "").trim());
3745
3961
  return {
3746
- installed: true,
3747
- authenticated: hasKey,
3748
- message: hasKey ? `Muse Spark ready via ${META_API_BASE_URL}` : `store a Meta key with \`vo-mcp set-key --provider meta\` or set ${META_API_KEY_ENV}`
3962
+ installed: false,
3963
+ authenticated: false,
3964
+ message: "Muse Spark coding is disabled; sanitized Model Firewall review only"
3749
3965
  };
3750
3966
  }
3751
3967
  };
@@ -3757,91 +3973,23 @@ var init_meta_runner = __esm({
3757
3973
  function resolveOaiBaseUrl(env2 = process.env) {
3758
3974
  return String(env2.VO_CODE_RUNNER_OAI_BASE_URL || "").trim();
3759
3975
  }
3760
- function resolveOaiModel(env2 = process.env) {
3761
- return String(env2.VO_CODE_RUNNER_OAI_MODEL || "").trim() || DEFAULT_OAI_MODEL;
3762
- }
3763
- function resolveOaiWireApi(env2 = process.env) {
3764
- const v = String(env2.VO_CODE_RUNNER_OAI_WIRE_API || "").trim().toLowerCase();
3765
- return v === "chat" || v === "responses" ? v : DEFAULT_OAI_WIRE_API;
3766
- }
3767
- function positiveIntEnv(raw) {
3768
- const n = Number(String(raw ?? "").trim());
3769
- return Number.isInteger(n) && n > 0 ? n : null;
3770
- }
3771
- function resolveOaiContextWindow(env2 = process.env) {
3772
- return positiveIntEnv(env2.VO_CODE_RUNNER_OAI_CONTEXT_WINDOW);
3773
- }
3774
- function resolveOaiMaxOutputTokens(env2 = process.env) {
3775
- return positiveIntEnv(env2.VO_CODE_RUNNER_OAI_MAX_OUTPUT_TOKENS);
3776
- }
3777
- function isCleanBaseUrl(url) {
3778
- return /^https?:\/\/[^\s"'`]+$/.test(url);
3779
- }
3780
- function buildOaiArgs(opts = {}, env2 = process.env) {
3781
- const baseUrl = resolveOaiBaseUrl(env2);
3782
- if (!baseUrl) {
3783
- throw new Error(
3784
- "openai-compatible runner: set VO_CODE_RUNNER_OAI_BASE_URL to an OpenAI-compatible endpoint (e.g. https://openrouter.ai/api/v1). Refusing to run with no explicit endpoint (fail-closed)."
3785
- );
3786
- }
3787
- if (!isCleanBaseUrl(baseUrl)) {
3788
- throw new Error(
3789
- `openai-compatible runner: VO_CODE_RUNNER_OAI_BASE_URL="${baseUrl}" is not a clean http(s) URL.`
3790
- );
3791
- }
3792
- const model = opts.model && String(opts.model).trim() ? String(opts.model).trim() : resolveOaiModel(env2);
3793
- const wireApi = resolveOaiWireApi(env2);
3794
- const args = [
3795
- "exec",
3796
- "--json",
3797
- "-c",
3798
- 'approval_policy="never"',
3799
- "--sandbox",
3800
- "danger-full-access",
3801
- "-c",
3802
- `model_providers.${PROVIDER_SLUG2}.name="BYO OpenAI-compatible"`,
3803
- "-c",
3804
- `model_providers.${PROVIDER_SLUG2}.base_url="${baseUrl}"`,
3805
- "-c",
3806
- `model_providers.${PROVIDER_SLUG2}.env_key="${OAI_API_KEY_ENV}"`,
3807
- "-c",
3808
- `model_providers.${PROVIDER_SLUG2}.wire_api="${wireApi}"`,
3809
- "-c",
3810
- `model_provider="${PROVIDER_SLUG2}"`,
3811
- "--model",
3812
- model
3813
- ];
3814
- if (opts.effort) {
3815
- args.push("-c", `model_reasoning_effort="${String(opts.effort)}"`);
3816
- }
3817
- const contextWindow = resolveOaiContextWindow(env2);
3818
- if (contextWindow) {
3819
- args.push("-c", `model_context_window=${contextWindow}`);
3820
- }
3821
- const maxOutputTokens = resolveOaiMaxOutputTokens(env2);
3822
- if (maxOutputTokens) {
3823
- args.push("-c", `model_max_output_tokens=${maxOutputTokens}`);
3824
- }
3825
- args.push("-");
3826
- return args;
3827
- }
3828
- var PROVIDER_SLUG2, OAI_API_KEY_ENV, DEFAULT_OAI_MODEL, DEFAULT_OAI_WIRE_API, OpenAICompatibleRunner, openaiCompatibleRunner;
3976
+ var OAI_API_KEY_ENV, OpenAICompatibleRunner, openaiCompatibleRunner;
3829
3977
  var init_openai_compatible_runner = __esm({
3830
3978
  "../../scripts/virtual-office/code-runner/openai-compatible-runner.mjs"() {
3831
3979
  "use strict";
3832
3980
  init_codex_runner();
3833
3981
  init_agent_key_store();
3834
- PROVIDER_SLUG2 = "vooai";
3835
3982
  OAI_API_KEY_ENV = "VO_CODE_RUNNER_OAI_API_KEY";
3836
- DEFAULT_OAI_MODEL = "deepseek/deepseek-chat";
3837
- DEFAULT_OAI_WIRE_API = "responses";
3838
3983
  OpenAICompatibleRunner = class {
3839
3984
  /** Codex is the transport binary. */
3840
3985
  get binary() {
3841
3986
  return resolveCodexBinary();
3842
3987
  }
3843
3988
  buildArgs(opts = {}) {
3844
- return buildOaiArgs(opts, process.env);
3989
+ void opts;
3990
+ throw new Error(
3991
+ "OpenAI-compatible full-repository coding is disabled. Use an explicit sanitized task capsule through the AlgoSuite Model Firewall."
3992
+ );
3845
3993
  }
3846
3994
  /** Codex JSONL events map identically → reuse the proven parser. */
3847
3995
  parseEvent(line) {
@@ -3865,31 +4013,10 @@ var init_openai_compatible_runner = __esm({
3865
4013
  }
3866
4014
  /** Best-effort: base URL chosen AND the codex transport is installed. */
3867
4015
  async checkAuth() {
3868
- const baseUrl = resolveOaiBaseUrl(process.env);
3869
- if (!baseUrl) {
3870
- return {
3871
- installed: false,
3872
- authenticated: false,
3873
- message: "set VO_CODE_RUNNER_OAI_BASE_URL to an OpenAI-compatible endpoint (fail-closed; no default)"
3874
- };
3875
- }
3876
- if (!isCleanBaseUrl(baseUrl)) {
3877
- return { installed: false, authenticated: false, message: `VO_CODE_RUNNER_OAI_BASE_URL is malformed: ${baseUrl}` };
3878
- }
3879
- const { CodexRunner: CodexRunner2 } = await Promise.resolve().then(() => (init_codex_runner(), codex_runner_exports));
3880
- const codexAuth = await new CodexRunner2().checkAuth();
3881
- if (!codexAuth.installed) {
3882
- return {
3883
- installed: false,
3884
- authenticated: false,
3885
- message: `codex transport not on PATH (npm i -g @openai/codex): ${codexAuth.message}`
3886
- };
3887
- }
3888
- const hasKey = Boolean(String(process.env[OAI_API_KEY_ENV] || "").trim());
3889
4016
  return {
3890
- installed: true,
3891
- authenticated: hasKey,
3892
- message: hasKey ? `ready \u2192 ${baseUrl}` : `set ${OAI_API_KEY_ENV} (or store it in the keychain) for ${baseUrl}`
4017
+ installed: false,
4018
+ authenticated: false,
4019
+ message: "OpenAI-compatible coding is disabled; sanitized Model Firewall task capsules only"
3893
4020
  };
3894
4021
  }
3895
4022
  };
@@ -4046,7 +4173,7 @@ var init_rate_limit_detector_core = __esm({
4046
4173
  });
4047
4174
 
4048
4175
  // ../../scripts/virtual-office/code-runner/rate-limit-resume.mjs
4049
- import { appendFileSync, mkdirSync as mkdirSync2 } from "node:fs";
4176
+ import { appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
4050
4177
  import { homedir as homedir2 } from "node:os";
4051
4178
  import { join as join2, dirname as dirname2 } from "node:path";
4052
4179
  function resumeQueuePath() {
@@ -4069,7 +4196,7 @@ function buildResumeEntry({ task = {}, resumeAfter = null, summary = "", at } =
4069
4196
  function recordRateLimited({ task = {}, resumeAfter = null, summary = "", queuePath = resumeQueuePath(), at = (/* @__PURE__ */ new Date()).toISOString() } = {}) {
4070
4197
  const entry = buildResumeEntry({ task, resumeAfter, summary, at });
4071
4198
  try {
4072
- mkdirSync2(dirname2(queuePath), { recursive: true });
4199
+ mkdirSync3(dirname2(queuePath), { recursive: true });
4073
4200
  appendFileSync(queuePath, `${JSON.stringify(entry)}
4074
4201
  `, "utf-8");
4075
4202
  return { ok: true, entry };
@@ -4161,8 +4288,8 @@ var init_auto_merge = __esm({
4161
4288
  });
4162
4289
 
4163
4290
  // ../../scripts/virtual-office/code-runner/pr-overlap-gate.mjs
4164
- import { spawnSync as spawnSync7 } from "node:child_process";
4165
- import path10 from "node:path";
4291
+ import { spawnSync as spawnSync8 } from "node:child_process";
4292
+ import path11 from "node:path";
4166
4293
  var init_pr_overlap_gate = __esm({
4167
4294
  "../../scripts/virtual-office/code-runner/pr-overlap-gate.mjs"() {
4168
4295
  "use strict";
@@ -4202,21 +4329,21 @@ var init_existing_pr_publication = __esm({
4202
4329
  });
4203
4330
 
4204
4331
  // ../../scripts/virtual-office/code-runner/publish.mjs
4205
- import { spawnSync as spawnSync8 } from "node:child_process";
4332
+ import { spawnSync as spawnSync9 } from "node:child_process";
4206
4333
  function parsePorcelainZ(out) {
4207
4334
  const tokens = String(out).split("\0");
4208
4335
  const files = [];
4209
4336
  for (let i = 0; i < tokens.length; i += 1) {
4210
4337
  const tok = tokens[i];
4211
4338
  if (!tok) continue;
4212
- const path17 = tok.slice(3);
4213
- if (path17) files.push(path17);
4339
+ const path18 = tok.slice(3);
4340
+ if (path18) files.push(path18);
4214
4341
  if (tok[0] === "R" || tok[0] === "C") i += 1;
4215
4342
  }
4216
4343
  return files;
4217
4344
  }
4218
- function isAgentScratch(path17) {
4219
- const p = String(path17 || "");
4345
+ function isAgentScratch(path18) {
4346
+ const p = String(path18 || "");
4220
4347
  return SCRATCH_PATTERNS.some((re) => re.test(p));
4221
4348
  }
4222
4349
  function isMaxTurnsResult(summary) {
@@ -4423,7 +4550,7 @@ var init_partial_pr_continuation = __esm({
4423
4550
  });
4424
4551
 
4425
4552
  // ../../scripts/virtual-office/code-runner/publish-async.mjs
4426
- import path11 from "node:path";
4553
+ import path12 from "node:path";
4427
4554
  function compactTitle(value, max = 100) {
4428
4555
  return String(value || "").replace(/\s+/g, " ").trim().slice(0, max) || "code-task";
4429
4556
  }
@@ -4465,7 +4592,7 @@ async function resolveOrCreateBranchAsync(worktreeDir, branchPrefix, runCommand
4465
4592
  return branch;
4466
4593
  }
4467
4594
  async function runLocalPrOverlapGateAsync(worktreeDir, files, { branch = "", env: env2 = process.env, excludePrNumber = null } = {}) {
4468
- const scriptPath = path11.join(worktreeDir, "scripts", "ci", "check-local-pr-overlap.mjs");
4595
+ const scriptPath = path12.join(worktreeDir, "scripts", "ci", "check-local-pr-overlap.mjs");
4469
4596
  try {
4470
4597
  const output = await runProcess2("node", [
4471
4598
  scriptPath,
@@ -4867,6 +4994,84 @@ var init_resume_branch = __esm({
4867
4994
  }
4868
4995
  });
4869
4996
 
4997
+ // ../../scripts/virtual-office/code-runner/skill-catalog.mjs
4998
+ import { readdirSync as readdirSync2, readFileSync as readFileSync3, statSync } from "node:fs";
4999
+ import { dirname as dirname3, join as join3 } from "node:path";
5000
+ import { fileURLToPath } from "node:url";
5001
+ function parseFrontmatterNameDescription(raw) {
5002
+ const text = String(raw).replace(/\r\n/g, "\n");
5003
+ if (!text.startsWith("---\n")) return null;
5004
+ const end = text.indexOf("\n---\n", 4);
5005
+ if (end === -1) return null;
5006
+ let name = "";
5007
+ let description = "";
5008
+ for (const line of text.slice(4, end).split("\n")) {
5009
+ const idx = line.indexOf(":");
5010
+ if (idx === -1) continue;
5011
+ const key = line.slice(0, idx).trim();
5012
+ const value = line.slice(idx + 1).trim();
5013
+ if (key === "name") name = value;
5014
+ else if (key === "description") description = value;
5015
+ }
5016
+ return name && description ? { name, description } : null;
5017
+ }
5018
+ function resolveDefaultRepoRoot() {
5019
+ const starts = [dirname3(fileURLToPath(import.meta.url)), process.cwd()];
5020
+ for (const start of starts) {
5021
+ let dir = start;
5022
+ for (let i = 0; i < 8; i += 1) {
5023
+ try {
5024
+ if (statSync(join3(dir, ".claude", "skills")).isDirectory()) return dir;
5025
+ } catch {
5026
+ }
5027
+ const parent = dirname3(dir);
5028
+ if (parent === dir) break;
5029
+ dir = parent;
5030
+ }
5031
+ }
5032
+ return process.cwd();
5033
+ }
5034
+ function loadSkillCatalog({ repoRoot: repoRoot2 = resolveDefaultRepoRoot() } = {}) {
5035
+ try {
5036
+ const skillsDir = join3(repoRoot2, ".claude", "skills");
5037
+ const catalog = [];
5038
+ for (const entry of readdirSync2(skillsDir)) {
5039
+ const dir = join3(skillsDir, entry);
5040
+ try {
5041
+ if (!statSync(dir).isDirectory()) continue;
5042
+ const parsed = parseFrontmatterNameDescription(
5043
+ readFileSync3(join3(dir, "SKILL.md"), "utf8")
5044
+ );
5045
+ if (parsed) catalog.push(parsed);
5046
+ } catch {
5047
+ }
5048
+ }
5049
+ return catalog.sort((a, b) => a.name.localeCompare(b.name)).slice(0, CATALOG_CAP);
5050
+ } catch {
5051
+ return [];
5052
+ }
5053
+ }
5054
+ function buildSkillCatalogBlock(catalog) {
5055
+ if (!Array.isArray(catalog) || catalog.length === 0) return "";
5056
+ const lines = catalog.map((s) => ` - ${s.name}: ${s.description}`);
5057
+ return [
5058
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ALGOSUITE SKILL CATALOG \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
5059
+ "The repo ships a skill corpus (same one Claude Code loads natively). When a",
5060
+ "task matches a skill below, LOAD ITS FULL INSTRUCTIONS FIRST and follow them:",
5061
+ " - via MCP: call vo_skill_get with the skill name (any vendor with AlgoHQ MCP tools), or",
5062
+ " - via file: read .claude/skills/<name>/SKILL.md in this worktree.",
5063
+ lines.join("\n"),
5064
+ ""
5065
+ ].join("\n");
5066
+ }
5067
+ var CATALOG_CAP;
5068
+ var init_skill_catalog = __esm({
5069
+ "../../scripts/virtual-office/code-runner/skill-catalog.mjs"() {
5070
+ "use strict";
5071
+ CATALOG_CAP = 60;
5072
+ }
5073
+ });
5074
+
4870
5075
  // ../../scripts/virtual-office/code-runner/dispatch-onboarding.mjs
4871
5076
  function buildDispatchOnboarding({ repo = "Algosuite-ai/Nexus" } = {}) {
4872
5077
  const reads = MANDATORY_READS.map((r, i) => ` ${i + 1}. ${r}`).join("\n");
@@ -4911,9 +5116,13 @@ function buildKnowledgeContextBlock(contextMarkdown) {
4911
5116
  }
4912
5117
  function composeDispatchPrompt(taskPrompt, opts = {}) {
4913
5118
  const knowledge = buildKnowledgeContextBlock(opts.knowledgeContextMarkdown);
5119
+ const catalog = opts.includeSkillCatalog === false ? "" : buildSkillCatalogBlock(
5120
+ opts.skillCatalog ?? loadSkillCatalog({ repoRoot: opts.repoRoot })
5121
+ );
4914
5122
  const task = String(taskPrompt ?? "").trim();
4915
5123
  return [
4916
5124
  buildDispatchOnboarding(opts),
5125
+ catalog,
4917
5126
  knowledge,
4918
5127
  "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 YOUR TASK \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
4919
5128
  task,
@@ -4924,6 +5133,7 @@ var MANDATORY_READS, NON_NEGOTIABLES;
4924
5133
  var init_dispatch_onboarding = __esm({
4925
5134
  "../../scripts/virtual-office/code-runner/dispatch-onboarding.mjs"() {
4926
5135
  "use strict";
5136
+ init_skill_catalog();
4927
5137
  MANDATORY_READS = [
4928
5138
  "CLAUDE.md (repo root \u2014 Claude-specific rules; auto-loaded, but READ it)",
4929
5139
  'AGENTS.md (repo root \u2014 cross-vendor rules + "Onboarding for a lane"; NOT auto-loaded)',
@@ -5060,8 +5270,8 @@ var init_task_prompt = __esm({
5060
5270
  // ../../scripts/virtual-office/code-runner/task-attachments.mjs
5061
5271
  import { createHash as createHash3, randomUUID } from "node:crypto";
5062
5272
  import { chmod, mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
5063
- import os from "node:os";
5064
- import path12 from "node:path";
5273
+ import os2 from "node:os";
5274
+ import path13 from "node:path";
5065
5275
  function safeTaskToken(taskId) {
5066
5276
  return String(taskId || "task").replace(/[^0-9A-Za-z_-]/gu, "_").slice(0, 48) || "task";
5067
5277
  }
@@ -5071,25 +5281,25 @@ function sanitizeTaskAttachmentName(name, index = 0) {
5071
5281
  return `${String(index + 1).padStart(2, "0")}-${normalized}`;
5072
5282
  }
5073
5283
  function assertGeneratedDirectory(directory, tempRoot) {
5074
- const resolvedDirectory = path12.resolve(directory);
5075
- const resolvedRoot = path12.resolve(tempRoot);
5076
- if (path12.dirname(resolvedDirectory) !== resolvedRoot || !path12.basename(resolvedDirectory).startsWith(DIRECTORY_PREFIX)) {
5284
+ const resolvedDirectory = path13.resolve(directory);
5285
+ const resolvedRoot = path13.resolve(tempRoot);
5286
+ if (path13.dirname(resolvedDirectory) !== resolvedRoot || !path13.basename(resolvedDirectory).startsWith(DIRECTORY_PREFIX)) {
5077
5287
  throw new Error("refusing to clean an unverified task-attachment directory");
5078
5288
  }
5079
5289
  return resolvedDirectory;
5080
5290
  }
5081
5291
  async function createAttachmentDirectory(taskId, tempRoot) {
5082
- const root = path12.resolve(tempRoot);
5292
+ const root = path13.resolve(tempRoot);
5083
5293
  await mkdir(root, { recursive: true });
5084
- const directory = await mkdtemp(path12.join(root, `${DIRECTORY_PREFIX}${safeTaskToken(taskId)}-`));
5085
- const marker = JSON.stringify({ owner: MARKER_OWNER, token: randomUUID(), directory: path12.basename(directory), created_at: (/* @__PURE__ */ new Date()).toISOString() });
5086
- await writeFile(path12.join(directory, MARKER_FILE), marker, { encoding: "utf8", mode: 384 });
5294
+ const directory = await mkdtemp(path13.join(root, `${DIRECTORY_PREFIX}${safeTaskToken(taskId)}-`));
5295
+ const marker = JSON.stringify({ owner: MARKER_OWNER, token: randomUUID(), directory: path13.basename(directory), created_at: (/* @__PURE__ */ new Date()).toISOString() });
5296
+ await writeFile(path13.join(directory, MARKER_FILE), marker, { encoding: "utf8", mode: 384 });
5087
5297
  return { directory, marker, tempRoot: root };
5088
5298
  }
5089
5299
  async function cleanupGeneratedDirectory(state) {
5090
5300
  if (!state || state.cleaned) return;
5091
5301
  const directory = assertGeneratedDirectory(state.directory, state.tempRoot);
5092
- const marker = await readFile(path12.join(directory, MARKER_FILE), "utf8").catch(() => "");
5302
+ const marker = await readFile(path13.join(directory, MARKER_FILE), "utf8").catch(() => "");
5093
5303
  if (marker !== state.marker) throw new Error("refusing to clean a task-attachment directory without its exact marker");
5094
5304
  await rm(directory, { recursive: true, force: true });
5095
5305
  state.cleaned = true;
@@ -5104,11 +5314,11 @@ function parseOwnedMarker(raw, directoryName) {
5104
5314
  }
5105
5315
  }
5106
5316
  async function sweepStaleTaskAttachmentDirectories({
5107
- tempRoot = os.tmpdir(),
5317
+ tempRoot = os2.tmpdir(),
5108
5318
  now = Date.now(),
5109
5319
  maxAgeMs = DEFAULT_STALE_AGE_MS
5110
5320
  } = {}) {
5111
- const root = path12.resolve(tempRoot);
5321
+ const root = path13.resolve(tempRoot);
5112
5322
  if (!Number.isFinite(maxAgeMs) || maxAgeMs <= 0) throw new Error("stale attachment age must be positive");
5113
5323
  const entries = await readdir(root, { withFileTypes: true }).catch((error) => {
5114
5324
  if (error?.code === "ENOENT") return [];
@@ -5117,8 +5327,8 @@ async function sweepStaleTaskAttachmentDirectories({
5117
5327
  let removed = 0;
5118
5328
  for (const entry of entries) {
5119
5329
  if (!entry.isDirectory() || !entry.name.startsWith(DIRECTORY_PREFIX)) continue;
5120
- const directory = assertGeneratedDirectory(path12.join(root, entry.name), root);
5121
- const markerRaw = await readFile(path12.join(directory, MARKER_FILE), "utf8").catch(() => "");
5330
+ const directory = assertGeneratedDirectory(path13.join(root, entry.name), root);
5331
+ const markerRaw = await readFile(path13.join(directory, MARKER_FILE), "utf8").catch(() => "");
5122
5332
  const marker = parseOwnedMarker(markerRaw, entry.name);
5123
5333
  if (!marker) continue;
5124
5334
  const directoryStat = await stat(directory);
@@ -5145,7 +5355,7 @@ function buildManifest(files) {
5145
5355
  "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 END UNTRUSTED TASK ATTACHMENTS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
5146
5356
  ].join("\n");
5147
5357
  }
5148
- async function materializeTaskAttachments(client, task, { tempRoot = os.tmpdir() } = {}) {
5358
+ async function materializeTaskAttachments(client, task, { tempRoot = os2.tmpdir() } = {}) {
5149
5359
  const refs = Array.isArray(task?.attachments) ? task.attachments : [];
5150
5360
  if (refs.length === 0) return { directory: null, files: [], manifestMarkdown: "", cleanup: async () => {
5151
5361
  } };
@@ -5161,10 +5371,10 @@ async function materializeTaskAttachments(client, task, { tempRoot = os.tmpdir()
5161
5371
  const sha256 = createHash3("sha256").update(content).digest("hex");
5162
5372
  if (sha256 !== ref.sha256) throw new Error(`attachment ${ref.attachment_id} sha256 mismatch`);
5163
5373
  const name = sanitizeTaskAttachmentName(ref.name, index);
5164
- const filePath = path12.join(state.directory, name);
5374
+ const filePath = path13.join(state.directory, name);
5165
5375
  await writeFile(filePath, content, { flag: "wx", mode: 384 });
5166
5376
  await chmod(filePath, 384);
5167
- files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path: path12.resolve(filePath) });
5377
+ files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path: path13.resolve(filePath) });
5168
5378
  }
5169
5379
  return { directory: state.directory, files, manifestMarkdown: buildManifest(files), cleanup: () => cleanupGeneratedDirectory(state) };
5170
5380
  } catch (error) {
@@ -5187,7 +5397,7 @@ var init_task_attachments = __esm({
5187
5397
 
5188
5398
  // ../../scripts/virtual-office/code-runner/session-spool-forwarder.mjs
5189
5399
  import { homedir as homedir3 } from "node:os";
5190
- import { join as join3 } from "node:path";
5400
+ import { join as join4 } from "node:path";
5191
5401
  import { readdir as readdir2, readFile as readFile2, unlink, writeFile as writeFile2 } from "node:fs/promises";
5192
5402
  import { createHash as createHash4 } from "node:crypto";
5193
5403
  function deriveUuid(seed) {
@@ -5219,18 +5429,18 @@ async function readSpool(spoolDir = SPOOL_DIR) {
5219
5429
  for (const f of files) {
5220
5430
  if (!f.endsWith(".json")) continue;
5221
5431
  try {
5222
- const record = JSON.parse(await readFile2(join3(spoolDir, f), "utf8"));
5432
+ const record = JSON.parse(await readFile2(join4(spoolDir, f), "utf8"));
5223
5433
  if (record && typeof record.session_key === "string") {
5224
- out.push({ full: join3(spoolDir, f), record });
5434
+ out.push({ full: join4(spoolDir, f), record });
5225
5435
  }
5226
5436
  } catch {
5227
5437
  }
5228
5438
  }
5229
5439
  return out;
5230
5440
  }
5231
- async function readCloudMap(path17) {
5441
+ async function readCloudMap(path18) {
5232
5442
  try {
5233
- return JSON.parse(await readFile2(path17, "utf8"));
5443
+ return JSON.parse(await readFile2(path18, "utf8"));
5234
5444
  } catch {
5235
5445
  return {};
5236
5446
  }
@@ -5303,8 +5513,8 @@ var SPOOL_DIR, CLOUD_MAP_FILE, STALE_MS, ACTIVE_SILENCE_MS;
5303
5513
  var init_session_spool_forwarder = __esm({
5304
5514
  "../../scripts/virtual-office/code-runner/session-spool-forwarder.mjs"() {
5305
5515
  "use strict";
5306
- SPOOL_DIR = join3(homedir3(), ".vo", "session-spool");
5307
- CLOUD_MAP_FILE = join3(homedir3(), ".vo", "session-cloud-map.json");
5516
+ SPOOL_DIR = join4(homedir3(), ".vo", "session-spool");
5517
+ CLOUD_MAP_FILE = join4(homedir3(), ".vo", "session-cloud-map.json");
5308
5518
  STALE_MS = 60 * 60 * 1e3;
5309
5519
  ACTIVE_SILENCE_MS = 10 * 60 * 1e3;
5310
5520
  }
@@ -5373,14 +5583,14 @@ var init_rate_limit_resume_scheduler_core = __esm({
5373
5583
  });
5374
5584
 
5375
5585
  // ../../scripts/virtual-office/code-runner/rate-limit-resume-scheduler.mjs
5376
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "node:fs";
5377
- import { dirname as dirname3, join as join4, resolve } from "node:path";
5586
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "node:fs";
5587
+ import { dirname as dirname4, join as join5, resolve } from "node:path";
5378
5588
  function log(msg) {
5379
5589
  console.log(`[rate-limit-scheduler ${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}`);
5380
5590
  }
5381
5591
  function readQueue(queuePath) {
5382
- if (!existsSync4(queuePath)) return [];
5383
- const content = readFileSync2(queuePath, "utf-8");
5592
+ if (!existsSync5(queuePath)) return [];
5593
+ const content = readFileSync4(queuePath, "utf-8");
5384
5594
  const lines = content.split("\n").filter((l) => l.trim());
5385
5595
  const entries = [];
5386
5596
  for (const line of lines) {
@@ -5393,18 +5603,18 @@ function readQueue(queuePath) {
5393
5603
  return entries;
5394
5604
  }
5395
5605
  function writeQueue(queuePath, entries) {
5396
- mkdirSync3(dirname3(queuePath), { recursive: true });
5606
+ mkdirSync4(dirname4(queuePath), { recursive: true });
5397
5607
  const lines = entries.map((e) => JSON.stringify(e)).join("\n");
5398
- writeFileSync2(queuePath, lines + (entries.length > 0 ? "\n" : ""), "utf-8");
5608
+ writeFileSync3(queuePath, lines + (entries.length > 0 ? "\n" : ""), "utf-8");
5399
5609
  }
5400
5610
  function attemptsStorePath() {
5401
- return join4(dirname3(resumeQueuePath()), "resume-attempts.json");
5611
+ return join5(dirname4(resumeQueuePath()), "resume-attempts.json");
5402
5612
  }
5403
5613
  function readAttemptsStore() {
5404
5614
  const p = attemptsStorePath();
5405
- if (!existsSync4(p)) return {};
5615
+ if (!existsSync5(p)) return {};
5406
5616
  try {
5407
- const parsed = JSON.parse(readFileSync2(p, "utf-8"));
5617
+ const parsed = JSON.parse(readFileSync4(p, "utf-8"));
5408
5618
  return parsed && typeof parsed === "object" ? parsed : {};
5409
5619
  } catch {
5410
5620
  return {};
@@ -5412,8 +5622,8 @@ function readAttemptsStore() {
5412
5622
  }
5413
5623
  function writeAttemptsStore(store) {
5414
5624
  const p = attemptsStorePath();
5415
- mkdirSync3(dirname3(p), { recursive: true });
5416
- writeFileSync2(p, JSON.stringify(store, null, 2), "utf-8");
5625
+ mkdirSync4(dirname4(p), { recursive: true });
5626
+ writeFileSync3(p, JSON.stringify(store, null, 2), "utf-8");
5417
5627
  }
5418
5628
  function countsFromStore(store) {
5419
5629
  const counts = {};
@@ -5797,9 +6007,9 @@ var init_agent_availability = __esm({
5797
6007
  // ../../scripts/virtual-office/code-runner/account-usage.mjs
5798
6008
  import { spawn as spawn4 } from "node:child_process";
5799
6009
  import fs6 from "node:fs";
5800
- import os2 from "node:os";
5801
- import path13 from "node:path";
5802
- function readClaudeUsage({ homeDir = os2.homedir(), read: rawRead = readJson } = {}) {
6010
+ import os3 from "node:os";
6011
+ import path14 from "node:path";
6012
+ function readClaudeUsage({ homeDir = os3.homedir(), read: rawRead = readJson } = {}) {
5803
6013
  const read = (p) => {
5804
6014
  try {
5805
6015
  return rawRead(p);
@@ -5807,7 +6017,7 @@ function readClaudeUsage({ homeDir = os2.homedir(), read: rawRead = readJson } =
5807
6017
  return null;
5808
6018
  }
5809
6019
  };
5810
- const status = read(path13.join(homeDir, ".claude", "claude-usage.json"));
6020
+ const status = read(path14.join(homeDir, ".claude", "claude-usage.json"));
5811
6021
  if (status && (status.seven_day || status.five_hour)) {
5812
6022
  const entry = {
5813
6023
  agent: "claude",
@@ -5816,7 +6026,7 @@ function readClaudeUsage({ homeDir = os2.homedir(), read: rawRead = readJson } =
5816
6026
  };
5817
6027
  if (entry.seven_day_used_pct !== null || entry.five_hour_used_pct !== null) return entry;
5818
6028
  }
5819
- const weekly = read(path13.join(homeDir, ".claude", "claude-weekly-usage.json"));
6029
+ const weekly = read(path14.join(homeDir, ".claude", "claude-weekly-usage.json"));
5820
6030
  if (weekly) {
5821
6031
  const entry = {
5822
6032
  agent: "claude",
@@ -5973,9 +6183,9 @@ var init_account_usage = __esm({
5973
6183
  });
5974
6184
 
5975
6185
  // ../../scripts/virtual-office/code-runner/ci-repair-evidence.mjs
5976
- import { spawnSync as spawnSync9 } from "node:child_process";
6186
+ import { spawnSync as spawnSync10 } from "node:child_process";
5977
6187
  function runGh(args) {
5978
- const result = spawnSync9("gh", args, { encoding: "utf8", timeout: 6e4, windowsHide: true });
6188
+ const result = spawnSync10("gh", args, { encoding: "utf8", timeout: 6e4, windowsHide: true });
5979
6189
  if (result.error) throw result.error;
5980
6190
  if (result.status !== 0) throw new Error((result.stderr || `gh ${args[0]} failed`).slice(-500));
5981
6191
  return result.stdout || "";
@@ -6138,11 +6348,11 @@ var init_superseded_pr_source = __esm({
6138
6348
 
6139
6349
  // ../../scripts/virtual-office/code-runner/pr-watcher.mjs
6140
6350
  import { homedir as homedir4 } from "node:os";
6141
- import { join as join5 } from "node:path";
6351
+ import { join as join6 } from "node:path";
6142
6352
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir2 } from "node:fs/promises";
6143
- import { spawnSync as spawnSync10 } from "node:child_process";
6353
+ import { spawnSync as spawnSync11 } from "node:child_process";
6144
6354
  function ghViewPr(prNumber, repo) {
6145
- const r = spawnSync10(
6355
+ const r = spawnSync11(
6146
6356
  "gh",
6147
6357
  ["pr", "view", String(prNumber), "-R", repo, "--json", "state,statusCheckRollup,headRefName,headRefOid,url,isDraft,mergeStateStatus"],
6148
6358
  { encoding: "utf8", timeout: 3e4 }
@@ -6233,7 +6443,7 @@ async function readState(stateFile) {
6233
6443
  }
6234
6444
  async function writeState(stateFile, state) {
6235
6445
  try {
6236
- await mkdir2(join5(stateFile, ".."), { recursive: true });
6446
+ await mkdir2(join6(stateFile, ".."), { recursive: true });
6237
6447
  await writeFile3(stateFile, JSON.stringify(state, null, 2), "utf8");
6238
6448
  } catch {
6239
6449
  }
@@ -6438,7 +6648,7 @@ var init_pr_watcher = __esm({
6438
6648
  init_pr_watcher_failure_confirmation();
6439
6649
  init_superseded_pr_source();
6440
6650
  init_superseded_pr_source();
6441
- DEFAULT_STATE_FILE = join5(homedir4(), ".vo", "dispatched-prs.json");
6651
+ DEFAULT_STATE_FILE = join6(homedir4(), ".vo", "dispatched-prs.json");
6442
6652
  FAIL_CONCLUSIONS = /* @__PURE__ */ new Set([
6443
6653
  "FAILURE",
6444
6654
  "TIMED_OUT",
@@ -6554,9 +6764,9 @@ function buildControlHandler({ getStatus, requestStop, allowedOrigin }) {
6554
6764
  res.end();
6555
6765
  return;
6556
6766
  }
6557
- const path17 = String(req.url || "").split("?")[0];
6767
+ const path18 = String(req.url || "").split("?")[0];
6558
6768
  res.setHeader("content-type", "application/json");
6559
- if (req.method === "GET" && path17 === "/status") {
6769
+ if (req.method === "GET" && path18 === "/status") {
6560
6770
  let status;
6561
6771
  try {
6562
6772
  status = getStatus();
@@ -6567,7 +6777,7 @@ function buildControlHandler({ getStatus, requestStop, allowedOrigin }) {
6567
6777
  res.end(JSON.stringify({ ok: true, ...status }));
6568
6778
  return;
6569
6779
  }
6570
- if (req.method === "POST" && path17 === "/stop") {
6780
+ if (req.method === "POST" && path18 === "/stop") {
6571
6781
  if (!isControlOriginAllowed(req.headers.origin, allowedOrigin) || !req.headers["x-vo-control"]) {
6572
6782
  res.statusCode = 403;
6573
6783
  res.end(JSON.stringify({ ok: false, error: "forbidden" }));
@@ -6678,44 +6888,45 @@ ${effortConfig.multiAgentInstruction}
6678
6888
  parts.push(String(basePrompt || "").trim());
6679
6889
  return parts.join("\n");
6680
6890
  }
6681
- var EFFORT_MODE_CONFIG, DEFAULT_MODE;
6891
+ var RED_TEAM_DIRECTIVE, EFFORT_MODE_CONFIG, DEFAULT_MODE;
6682
6892
  var init_effort_mode_config = __esm({
6683
6893
  "../../scripts/virtual-office/code-runner/effort-mode-config.mjs"() {
6684
6894
  "use strict";
6895
+ RED_TEAM_DIRECTIVE = "Before declaring done, red-team your own work: name the top ways it could be wrong \u2014 especially code that is correct but silently not wired into production callers \u2014 give the failure scenario for each, and state the evidence that rules it out.";
6685
6896
  EFFORT_MODE_CONFIG = {
6686
6897
  fast: {
6687
6898
  tier: "cheap",
6688
6899
  permissionMode: "acceptEdits",
6689
6900
  maxTurns: 80,
6690
- thinkingDirective: "",
6901
+ thinkingDirective: RED_TEAM_DIRECTIVE,
6691
6902
  multiAgentInstruction: ""
6692
6903
  },
6693
6904
  standard: {
6694
6905
  tier: "mid",
6695
6906
  permissionMode: "acceptEdits",
6696
6907
  maxTurns: 200,
6697
- thinkingDirective: "",
6908
+ thinkingDirective: RED_TEAM_DIRECTIVE,
6698
6909
  multiAgentInstruction: ""
6699
6910
  },
6700
6911
  deep: {
6701
6912
  tier: "best",
6702
6913
  permissionMode: "acceptEdits",
6703
6914
  maxTurns: 300,
6704
- thinkingDirective: "Think step-by-step. Verify assumptions against source code. Check edge cases.",
6915
+ thinkingDirective: `Think step-by-step. Verify assumptions against source code. Check edge cases. ${RED_TEAM_DIRECTIVE}`,
6705
6916
  multiAgentInstruction: ""
6706
6917
  },
6707
6918
  ultra: {
6708
6919
  tier: "best",
6709
6920
  permissionMode: "acceptEdits",
6710
6921
  maxTurns: 500,
6711
- thinkingDirective: "Think step-by-step. Exhaustively verify every assumption against source code and documentation. Adversarially review your own work.",
6922
+ thinkingDirective: `Think step-by-step. Exhaustively verify every assumption against source code and documentation. ${RED_TEAM_DIRECTIVE}`,
6712
6923
  multiAgentInstruction: "If this task needs multiple phases (research, build, verify), propose a plan first."
6713
6924
  },
6714
6925
  ultracode: {
6715
6926
  tier: "best",
6716
6927
  permissionMode: "acceptEdits",
6717
6928
  maxTurns: 800,
6718
- thinkingDirective: "Think step-by-step. Exhaustively verify every assumption against source code and documentation. Build worked examples to validate correctness. Adversarially review your own work.",
6929
+ thinkingDirective: `Think step-by-step. Exhaustively verify every assumption against source code and documentation. Build worked examples to validate correctness. ${RED_TEAM_DIRECTIVE}`,
6719
6930
  multiAgentInstruction: "Decompose this work into parallel research, build, and verification streams; use workflow orchestration where it helps."
6720
6931
  }
6721
6932
  };
@@ -6725,8 +6936,8 @@ var init_effort_mode_config = __esm({
6725
6936
 
6726
6937
  // ../../scripts/virtual-office/model-registry.mjs
6727
6938
  import fs7 from "node:fs";
6728
- import path14 from "node:path";
6729
- import { fileURLToPath } from "node:url";
6939
+ import path15 from "node:path";
6940
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
6730
6941
  function uniqueModels(models = []) {
6731
6942
  return [...new Set(models.map((model) => String(model || "").trim()).filter(Boolean))];
6732
6943
  }
@@ -6848,7 +7059,7 @@ function readCache(cacheFile = DEFAULT_CACHE_FILE, nowMs = Date.now(), ttlMs = D
6848
7059
  }
6849
7060
  }
6850
7061
  function writeCache(cacheFile = DEFAULT_CACHE_FILE, payload) {
6851
- fs7.mkdirSync(path14.dirname(cacheFile), { recursive: true });
7062
+ fs7.mkdirSync(path15.dirname(cacheFile), { recursive: true });
6852
7063
  fs7.writeFileSync(cacheFile, JSON.stringify(payload, null, 2));
6853
7064
  }
6854
7065
  async function fetchRegistryCatalog({
@@ -6906,10 +7117,10 @@ var __dirname, ROOT, DEFAULT_CACHE_DIR, DEFAULT_CACHE_FILE, DEFAULT_TTL_MS3, ANT
6906
7117
  var init_model_registry = __esm({
6907
7118
  "../../scripts/virtual-office/model-registry.mjs"() {
6908
7119
  "use strict";
6909
- __dirname = path14.dirname(fileURLToPath(import.meta.url));
6910
- ROOT = path14.resolve(__dirname, "..", "..");
6911
- DEFAULT_CACHE_DIR = path14.join(ROOT, ".virtual-office-cache", "model-registry");
6912
- DEFAULT_CACHE_FILE = path14.join(DEFAULT_CACHE_DIR, "catalog.json");
7120
+ __dirname = path15.dirname(fileURLToPath2(import.meta.url));
7121
+ ROOT = path15.resolve(__dirname, "..", "..");
7122
+ DEFAULT_CACHE_DIR = path15.join(ROOT, ".virtual-office-cache", "model-registry");
7123
+ DEFAULT_CACHE_FILE = path15.join(DEFAULT_CACHE_DIR, "catalog.json");
6913
7124
  DEFAULT_TTL_MS3 = 60 * 60 * 1e3;
6914
7125
  ANTHROPIC_API_VERSION = "2023-06-01";
6915
7126
  FAMILY_DEFINITIONS = {
@@ -6969,6 +7180,42 @@ var init_model_registry = __esm({
6969
7180
  }
6970
7181
  });
6971
7182
 
7183
+ // ../../scripts/virtual-office/code-runner/meta-model-catalog.mjs
7184
+ function normalizeMetaEffort(value) {
7185
+ const normalized = String(value || "").trim().toLowerCase();
7186
+ if (["low", "medium", "high", "xhigh"].includes(normalized)) return normalized;
7187
+ if (normalized === "max") return "xhigh";
7188
+ return null;
7189
+ }
7190
+ function resolveMetaModelForTier() {
7191
+ return META_DEFAULT_MODEL;
7192
+ }
7193
+ function resolveMetaEffortForTier(tier = "mid") {
7194
+ return TIER_EFFORT[tier] || TIER_EFFORT.mid;
7195
+ }
7196
+ function resolveMetaEffortForRung(rung = "R3") {
7197
+ return RUNG_EFFORT[rung] || RUNG_EFFORT.R3;
7198
+ }
7199
+ var META_DEFAULT_MODEL, TIER_EFFORT, RUNG_EFFORT;
7200
+ var init_meta_model_catalog = __esm({
7201
+ "../../scripts/virtual-office/code-runner/meta-model-catalog.mjs"() {
7202
+ "use strict";
7203
+ META_DEFAULT_MODEL = "muse-spark-1.1";
7204
+ TIER_EFFORT = Object.freeze({
7205
+ cheap: "low",
7206
+ mid: "medium",
7207
+ best: "xhigh"
7208
+ });
7209
+ RUNG_EFFORT = Object.freeze({
7210
+ R1: "low",
7211
+ R2: "medium",
7212
+ R3: "medium",
7213
+ R4: "high",
7214
+ R5: "xhigh"
7215
+ });
7216
+ }
7217
+ });
7218
+
6972
7219
  // ../../scripts/virtual-office/code-runner/model-router.mjs
6973
7220
  function normalizeAgent(agent = DEFAULT_AGENT2) {
6974
7221
  const normalized = String(agent || DEFAULT_AGENT2).trim().toLowerCase();
@@ -7450,9 +7697,9 @@ var init_classify_task = __esm({
7450
7697
  });
7451
7698
 
7452
7699
  // ../../scripts/virtual-office/code-runner/auto-router/effort-policy.mjs
7453
- import { readFileSync as readFileSync3 } from "node:fs";
7700
+ import { readFileSync as readFileSync5 } from "node:fs";
7454
7701
  import { homedir as homedir5 } from "node:os";
7455
- import { join as join6 } from "node:path";
7702
+ import { join as join7 } from "node:path";
7456
7703
  function difficultyToRung(difficulty, thresholds) {
7457
7704
  const b = thresholds.rungBounds;
7458
7705
  if (difficulty >= b.R5) return "R5";
@@ -7477,9 +7724,9 @@ function operatorTierToRung(tier, difficulty, thresholds) {
7477
7724
  if (tier === "best" && difficulty >= thresholds.rungBounds.R5) return "R5";
7478
7725
  return base;
7479
7726
  }
7480
- function readCodexModelsCache({ path: path17 = DEFAULT_CODEX_MODELS_CACHE, read = readFileSync3 } = {}) {
7727
+ function readCodexModelsCache({ path: path18 = DEFAULT_CODEX_MODELS_CACHE, read = readFileSync5 } = {}) {
7481
7728
  try {
7482
- const parsed = JSON.parse(read(path17, "utf8"));
7729
+ const parsed = JSON.parse(read(path18, "utf8"));
7483
7730
  return Array.isArray(parsed?.models) ? parsed : null;
7484
7731
  } catch {
7485
7732
  return null;
@@ -7529,23 +7776,148 @@ var init_effort_policy = __esm({
7529
7776
  init_meta_model_catalog();
7530
7777
  RUNG_ORDER = ["R1", "R2", "R3", "R4", "R5"];
7531
7778
  rungIndex = (rung) => RUNG_ORDER.indexOf(rung);
7532
- DEFAULT_CODEX_MODELS_CACHE = join6(homedir5(), ".codex", "models_cache.json");
7779
+ DEFAULT_CODEX_MODELS_CACHE = join7(homedir5(), ".codex", "models_cache.json");
7780
+ }
7781
+ });
7782
+
7783
+ // ../../scripts/virtual-office/code-runner/auto-router/role-cost-shadow.mjs
7784
+ function attributeRoleCosts({ plannerTokens, workerTokens, plannerModelRate, workerModelRate } = {}) {
7785
+ const inputs = { plannerTokens, workerTokens, plannerModelRate, workerModelRate };
7786
+ for (const [name, value] of Object.entries(inputs)) {
7787
+ if (!isNonNegativeFinite(value)) {
7788
+ return {
7789
+ valid: false,
7790
+ reason: `invalid ${name} (${String(value)}) \u2014 fail-open, no attribution`,
7791
+ ...EMPTY_ATTRIBUTION
7792
+ };
7793
+ }
7794
+ }
7795
+ const plannerCostUsd = plannerTokens * plannerModelRate;
7796
+ const workerCostUsd = workerTokens * workerModelRate;
7797
+ const totalCostUsd = plannerCostUsd + workerCostUsd;
7798
+ const totalTokens = plannerTokens + workerTokens;
7799
+ const plannerCostShare = totalCostUsd > 0 ? plannerCostUsd / totalCostUsd : null;
7800
+ const workerCostShare = totalCostUsd > 0 ? workerCostUsd / totalCostUsd : null;
7801
+ const plannerTokenShare = totalTokens > 0 ? plannerTokens / totalTokens : null;
7802
+ const workerTokenShare = totalTokens > 0 ? workerTokens / totalTokens : null;
7803
+ const plannerCostShareRatio = plannerCostShare !== null && plannerTokenShare !== null && plannerTokenShare > 0 ? plannerCostShare / plannerTokenShare : null;
7804
+ return {
7805
+ valid: true,
7806
+ plannerCostUsd,
7807
+ workerCostUsd,
7808
+ totalCostUsd,
7809
+ plannerCostShare,
7810
+ workerCostShare,
7811
+ plannerTokenShare,
7812
+ workerTokenShare,
7813
+ plannerCostShareRatio
7814
+ };
7815
+ }
7816
+ function shadowFanOutGate({ taskClass, disagreementSignal, confidence, panelSize } = {}, { thresholds } = {}) {
7817
+ const cfg = { ...DEFAULT_SHADOW_FAN_OUT, ...thresholds?.shadowFanOut ?? {} };
7818
+ const defaultsUsed = !thresholds?.shadowFanOut;
7819
+ const no = (reason) => ({ wouldFanOut: false, reason, criterion: SHADOW_CRITERION, defaultsUsed });
7820
+ if (!isUnitInterval(disagreementSignal)) {
7821
+ return no(`invalid disagreementSignal (${String(disagreementSignal)}) \u2014 fail-open, single-model`);
7822
+ }
7823
+ if (!isUnitInterval(confidence)) {
7824
+ return no(`invalid confidence (${String(confidence)}) \u2014 fail-open, single-model`);
7825
+ }
7826
+ const size = panelSize === void 0 || panelSize === null ? cfg.defaultPanelSize : panelSize;
7827
+ if (!Number.isInteger(size) || size < 1) {
7828
+ return no(`invalid panelSize (${String(panelSize)}) \u2014 fail-open, single-model`);
7829
+ }
7830
+ const never = Array.isArray(cfg.neverFanOutClasses) ? cfg.neverFanOutClasses : [];
7831
+ if (typeof taskClass === "string" && never.includes(taskClass)) {
7832
+ return no(`class=${taskClass} in neverFanOutClasses \u2014 fan-out never pays on low-stakes classes`);
7833
+ }
7834
+ if (size < cfg.minPanelSize) {
7835
+ return no(`panelSize ${size} < ${cfg.minPanelSize} \u2014 too small to contribute independent signal`);
7836
+ }
7837
+ if (disagreementSignal < cfg.minDisagreementSignal) {
7838
+ return no(`disagreement ${disagreementSignal} < ${cfg.minDisagreementSignal} \u2014 extra models would confirm, not inform`);
7839
+ }
7840
+ if (confidence > cfg.maxSingleModelConfidence) {
7841
+ return no(`confidence ${confidence} > ${cfg.maxSingleModelConfidence} \u2014 single model already confident; fan-out adds cost, not signal`);
7842
+ }
7843
+ return {
7844
+ wouldFanOut: true,
7845
+ reason: `disagreement ${disagreementSignal} \u2265 ${cfg.minDisagreementSignal} AND confidence ${confidence} \u2264 ${cfg.maxSingleModelConfidence} (panel ${size})`,
7846
+ criterion: SHADOW_CRITERION,
7847
+ defaultsUsed
7848
+ };
7849
+ }
7850
+ function buildShadowRecords({ decision, task = {}, thresholds, roleCostInputs = null } = {}) {
7851
+ if (!decision || typeof decision !== "object") return [];
7852
+ const base = {
7853
+ shadow: true,
7854
+ routerVersion: decision.routerVersion ?? null,
7855
+ ts: decision.ts ?? null,
7856
+ taskId: task?.id ?? null
7857
+ };
7858
+ const roleCost = roleCostInputs ? attributeRoleCosts(roleCostInputs) : { valid: false, reason: "planner/worker token telemetry unavailable at routing time", ...EMPTY_ATTRIBUTION };
7859
+ const hasTaskSignal = typeof task?.disagreement_signal === "number";
7860
+ const disagreementSignal = hasTaskSignal ? task.disagreement_signal : typeof decision.difficulty === "number" ? decision.difficulty / 100 : void 0;
7861
+ const gate = shadowFanOutGate(
7862
+ {
7863
+ taskClass: decision.taskClass,
7864
+ disagreementSignal,
7865
+ confidence: decision.confidence,
7866
+ panelSize: task?.panel_size
7867
+ },
7868
+ { thresholds }
7869
+ );
7870
+ return [
7871
+ { kind: "shadow_role_cost", ...base, roleCost },
7872
+ {
7873
+ kind: "shadow_fan_out",
7874
+ ...base,
7875
+ disagreementSignal: disagreementSignal ?? null,
7876
+ disagreementSource: hasTaskSignal ? "task.disagreement_signal" : "difficulty-proxy-v0",
7877
+ ...gate
7878
+ }
7879
+ ];
7880
+ }
7881
+ var SHADOW_CRITERION, DEFAULT_SHADOW_FAN_OUT, isNonNegativeFinite, isUnitInterval, EMPTY_ATTRIBUTION;
7882
+ var init_role_cost_shadow = __esm({
7883
+ "../../scripts/virtual-office/code-runner/auto-router/role-cost-shadow.mjs"() {
7884
+ "use strict";
7885
+ SHADOW_CRITERION = "info-bottleneck-v0";
7886
+ DEFAULT_SHADOW_FAN_OUT = Object.freeze({
7887
+ minDisagreementSignal: 0.4,
7888
+ maxSingleModelConfidence: 0.6,
7889
+ minPanelSize: 2,
7890
+ defaultPanelSize: 3,
7891
+ neverFanOutClasses: Object.freeze(["chore", "docs"])
7892
+ });
7893
+ isNonNegativeFinite = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0;
7894
+ isUnitInterval = (n) => isNonNegativeFinite(n) && n <= 1;
7895
+ EMPTY_ATTRIBUTION = Object.freeze({
7896
+ plannerCostUsd: null,
7897
+ workerCostUsd: null,
7898
+ totalCostUsd: null,
7899
+ plannerCostShare: null,
7900
+ workerCostShare: null,
7901
+ plannerTokenShare: null,
7902
+ workerTokenShare: null,
7903
+ plannerCostShareRatio: null
7904
+ });
7533
7905
  }
7534
7906
  });
7535
7907
 
7536
7908
  // ../../scripts/virtual-office/code-runner/auto-router/auto-router.mjs
7537
- import { readFileSync as readFileSync4, appendFileSync as appendFileSync2, mkdirSync as mkdirSync4 } from "node:fs";
7909
+ import { readFileSync as readFileSync6, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5 } from "node:fs";
7538
7910
  import { homedir as homedir6 } from "node:os";
7539
- import { join as join7, dirname as dirname4 } from "node:path";
7540
- import { fileURLToPath as fileURLToPath2 } from "node:url";
7911
+ import { join as join8, dirname as dirname5 } from "node:path";
7912
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
7541
7913
  function getAutoRouterMode(env2 = process.env) {
7542
7914
  const raw = String(env2.VO_CODE_RUNNER_AUTO_ROUTER || "").trim().toLowerCase();
7543
7915
  return MODES.has(raw) ? raw : "off";
7544
7916
  }
7545
7917
  function loadThresholds() {
7546
7918
  if (!cachedThresholds) {
7547
- const here = dirname4(fileURLToPath2(import.meta.url));
7548
- cachedThresholds = JSON.parse(readFileSync4(join7(here, "thresholds.json"), "utf8"));
7919
+ const here = dirname5(fileURLToPath3(import.meta.url));
7920
+ cachedThresholds = JSON.parse(readFileSync6(join8(here, "thresholds.json"), "utf8"));
7549
7921
  }
7550
7922
  return cachedThresholds;
7551
7923
  }
@@ -7611,16 +7983,36 @@ function formatDecisionReason(decision, maxLen = 480) {
7611
7983
  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("; ")}`;
7612
7984
  return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
7613
7985
  }
7614
- var ROUTER_VERSION, DECISION_FALLBACK_PATH, MODES, cachedThresholds;
7986
+ function appendDecisionFallback(decision, { path: path18 = DECISION_FALLBACK_PATH, append = appendFileSync2, mkdir: mkdir3 = mkdirSync5, task, thresholds, roleCostInputs } = {}) {
7987
+ try {
7988
+ mkdir3(dirname5(path18), { recursive: true });
7989
+ append(path18, `${JSON.stringify(decision)}
7990
+ `, "utf8");
7991
+ if (isRouterDecision(decision)) {
7992
+ try {
7993
+ const records = buildShadowRecords({ decision, task, thresholds: thresholds || loadThresholds(), roleCostInputs });
7994
+ for (const record of records) append(path18, `${JSON.stringify(record)}
7995
+ `, "utf8");
7996
+ } catch {
7997
+ }
7998
+ }
7999
+ return true;
8000
+ } catch {
8001
+ return false;
8002
+ }
8003
+ }
8004
+ var ROUTER_VERSION, DECISION_FALLBACK_PATH, MODES, cachedThresholds, isRouterDecision;
7615
8005
  var init_auto_router = __esm({
7616
8006
  "../../scripts/virtual-office/code-runner/auto-router/auto-router.mjs"() {
7617
8007
  "use strict";
7618
8008
  init_classify_task();
7619
8009
  init_effort_policy();
8010
+ init_role_cost_shadow();
7620
8011
  ROUTER_VERSION = "0.1.0";
7621
- DECISION_FALLBACK_PATH = join7(homedir6(), ".claude", "vo-auto-router-decisions.jsonl");
8012
+ DECISION_FALLBACK_PATH = join8(homedir6(), ".claude", "vo-auto-router-decisions.jsonl");
7622
8013
  MODES = /* @__PURE__ */ new Set(["off", "shadow", "on"]);
7623
8014
  cachedThresholds = null;
8015
+ isRouterDecision = (d) => Boolean(d && typeof d === "object" && typeof d.taskClass === "string" && typeof d.confidence === "number");
7624
8016
  }
7625
8017
  });
7626
8018
 
@@ -7652,7 +8044,7 @@ function resolveAgentEffort({ agent, tier, env: env2, applying, decision }) {
7652
8044
  }
7653
8045
  return applying ? decision.effort ?? null : null;
7654
8046
  }
7655
- async function resolveEffortDispatch({ client, task, agent = "claude", env: env2, basePrompt, resolveModel = resolveTaskModel, route = routeTask }) {
8047
+ async function resolveEffortDispatch({ client, task, agent = "claude", env: env2, basePrompt, resolveModel = resolveTaskModel, route = routeTask, appendDecision = appendDecisionFallback }) {
7656
8048
  const dispatchMode = task.dispatch_mode ?? await client.getDispatchMode().catch(() => "standard");
7657
8049
  const effortConfig = resolveEffortMode(dispatchMode);
7658
8050
  const routerMode = getAutoRouterMode(env2);
@@ -7671,6 +8063,12 @@ async function resolveEffortDispatch({ client, task, agent = "claude", env: env2
7671
8063
  { agent }
7672
8064
  );
7673
8065
  const effort = resolveAgentEffort({ agent, tier, env: env2, applying, decision });
8066
+ if (decision) {
8067
+ try {
8068
+ appendDecision(decision, { task });
8069
+ } catch {
8070
+ }
8071
+ }
7674
8072
  return {
7675
8073
  dispatchMode,
7676
8074
  routerMode,
@@ -7865,26 +8263,66 @@ function safeIdentityPart(value, fallback) {
7865
8263
  const normalized = String(value || "").trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
7866
8264
  return normalized || fallback;
7867
8265
  }
8266
+ function safeBaseEnv(env2 = {}) {
8267
+ const result = {};
8268
+ for (const [key, value] of Object.entries(env2)) {
8269
+ if (value !== void 0 && SAFE_ENV_NAMES.has(key.toUpperCase())) result[key] = value;
8270
+ }
8271
+ return result;
8272
+ }
7868
8273
  function buildAgentProcessEnv(env2, { agent = "agent", runnerId = "vo-runner", taskId = "task" } = {}) {
7869
- if (String(env2?.AGENT_ID || "").trim()) return env2;
8274
+ const base = safeBaseEnv(env2);
8275
+ if (String(env2?.AGENT_ID || "").trim()) return { ...base, AGENT_ID: env2.AGENT_ID };
7870
8276
  const generated = [
7871
8277
  "vo",
7872
8278
  safeIdentityPart(agent, "agent"),
7873
8279
  safeIdentityPart(runnerId, "runner"),
7874
8280
  safeIdentityPart(taskId, "task").slice(0, 12)
7875
8281
  ].join("-");
7876
- return { ...env2, AGENT_ID: generated };
8282
+ return { ...base, AGENT_ID: generated };
7877
8283
  }
8284
+ var SAFE_ENV_NAMES;
7878
8285
  var init_agent_process_env = __esm({
7879
8286
  "../../scripts/virtual-office/code-runner/agent-process-env.mjs"() {
7880
8287
  "use strict";
8288
+ SAFE_ENV_NAMES = /* @__PURE__ */ new Set([
8289
+ "AGENT_ID",
8290
+ "APPDATA",
8291
+ "CI",
8292
+ "COLORTERM",
8293
+ "COMSPEC",
8294
+ "FORCE_COLOR",
8295
+ "HOME",
8296
+ "HOMEDRIVE",
8297
+ "HOMEPATH",
8298
+ "LANG",
8299
+ "LOCALAPPDATA",
8300
+ "LOGONSERVER",
8301
+ "NO_COLOR",
8302
+ "NUMBER_OF_PROCESSORS",
8303
+ "OS",
8304
+ "PATH",
8305
+ "PATHEXT",
8306
+ "PROCESSOR_ARCHITECTURE",
8307
+ "PROGRAMDATA",
8308
+ "SYSTEMDRIVE",
8309
+ "SYSTEMROOT",
8310
+ "TEMP",
8311
+ "TERM",
8312
+ "TMP",
8313
+ "TMPDIR",
8314
+ "USERDOMAIN",
8315
+ "USERNAME",
8316
+ "USERPROFILE",
8317
+ "WINDIR"
8318
+ ]);
7881
8319
  }
7882
8320
  });
7883
8321
 
7884
8322
  // ../../scripts/virtual-office/code-runner/isolation-audit.mjs
7885
8323
  import fs8 from "node:fs";
7886
8324
  import fsp9 from "node:fs/promises";
7887
- import path15 from "node:path";
8325
+ import path16 from "node:path";
7888
8326
  async function defaultRun(command, args, cwd, options = {}) {
7889
8327
  return runProcess2(command, args, { cwd, timeout: 6e4, ...options });
7890
8328
  }
@@ -7897,7 +8335,7 @@ async function canonicalRootForWorktree(worktreeDir, run) {
7897
8335
  "--path-format=absolute",
7898
8336
  "--git-common-dir"
7899
8337
  ])).trim();
7900
- const root = path15.dirname(commonDir);
8338
+ const root = path16.dirname(commonDir);
7901
8339
  return samePath2(root, worktreeDir) ? null : root;
7902
8340
  }
7903
8341
  async function snapshot(root, run) {
@@ -7939,21 +8377,21 @@ async function changedPaths(root, run) {
7939
8377
  }
7940
8378
  async function quarantineCanonicalWrites({ baseline, worktreeDir, taskId, run, now }) {
7941
8379
  const paths = await changedPaths(baseline.root, run);
7942
- const quarantineDir = path15.join(
7943
- path15.dirname(worktreeDir),
8380
+ const quarantineDir = path16.join(
8381
+ path16.dirname(worktreeDir),
7944
8382
  ".canonical-recovery",
7945
8383
  `${String(taskId || "unknown").replace(/[^a-z0-9-]/gi, "-")}-${now().toISOString().replace(/[:.]/g, "-")}`
7946
8384
  );
7947
8385
  await fsp9.mkdir(quarantineDir, { recursive: true });
7948
8386
  const patch = await git2(run, baseline.root, ["diff", "--binary", "HEAD"], { raw: true });
7949
- await fsp9.writeFile(path15.join(quarantineDir, "tracked.patch"), patch, "utf8");
8387
+ await fsp9.writeFile(path16.join(quarantineDir, "tracked.patch"), patch, "utf8");
7950
8388
  for (const relative of paths.untracked) {
7951
- const source = path15.join(baseline.root, relative);
7952
- const target = path15.join(quarantineDir, "untracked", relative);
7953
- await fsp9.mkdir(path15.dirname(target), { recursive: true });
8389
+ const source = path16.join(baseline.root, relative);
8390
+ const target = path16.join(quarantineDir, "untracked", relative);
8391
+ await fsp9.mkdir(path16.dirname(target), { recursive: true });
7954
8392
  await fsp9.copyFile(source, target);
7955
8393
  }
7956
- await fsp9.writeFile(path15.join(quarantineDir, "manifest.json"), `${JSON.stringify({
8394
+ await fsp9.writeFile(path16.join(quarantineDir, "manifest.json"), `${JSON.stringify({
7957
8395
  taskId,
7958
8396
  canonicalRoot: baseline.root,
7959
8397
  canonicalHead: baseline.head,
@@ -7975,8 +8413,8 @@ async function restoreExactCanonicalPaths(baseline, evidence, run) {
7975
8413
  ]);
7976
8414
  }
7977
8415
  for (const relative of evidence.untracked) {
7978
- const target = path15.resolve(baseline.root, relative);
7979
- const prefix = `${path15.resolve(baseline.root)}${path15.sep}`;
8416
+ const target = path16.resolve(baseline.root, relative);
8417
+ const prefix = `${path16.resolve(baseline.root)}${path16.sep}`;
7980
8418
  if (!target.startsWith(prefix) || !fs8.existsSync(target)) continue;
7981
8419
  await fsp9.rm(target, { force: true });
7982
8420
  }
@@ -8013,7 +8451,7 @@ var init_isolation_audit = __esm({
8013
8451
  init_process_runner2();
8014
8452
  splitZ2 = (value) => String(value || "").split("\0").map((item) => item.trim()).filter(Boolean);
8015
8453
  samePath2 = (left, right) => {
8016
- const [a, b] = [left, right].map((value) => path15.resolve(value));
8454
+ const [a, b] = [left, right].map((value) => path16.resolve(value));
8017
8455
  return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
8018
8456
  };
8019
8457
  }
@@ -8022,7 +8460,7 @@ var init_isolation_audit = __esm({
8022
8460
  // ../../scripts/virtual-office/code-runner/recovery-ledger.mjs
8023
8461
  import fs9 from "node:fs";
8024
8462
  import fsp10 from "node:fs/promises";
8025
- import path16 from "node:path";
8463
+ import path17 from "node:path";
8026
8464
  function recoveryTaskId(prompt) {
8027
8465
  const match = String(prompt || "").match(/VO_RECOVERY_FROM_CODE_TASK:\s*([0-9a-f-]{36})/i);
8028
8466
  return match ? match[1].toLowerCase() : null;
@@ -8036,10 +8474,10 @@ function cloneLeaf(repo) {
8036
8474
  function recoveryLedgerCandidates(repo, clonesRoot2) {
8037
8475
  const leaf = cloneLeaf(repo);
8038
8476
  if (!leaf || !clonesRoot2) return [];
8039
- const canonical = path16.join(clonesRoot2, leaf);
8477
+ const canonical = path17.join(clonesRoot2, leaf);
8040
8478
  return [
8041
- path16.join(clonesRoot2, ".agent-worktrees", leaf, "recovery-ledger.jsonl"),
8042
- path16.join(canonical, ".agent-worktrees", "recovery-ledger.jsonl")
8479
+ path17.join(clonesRoot2, ".agent-worktrees", leaf, "recovery-ledger.jsonl"),
8480
+ path17.join(canonical, ".agent-worktrees", "recovery-ledger.jsonl")
8043
8481
  ];
8044
8482
  }
8045
8483
  async function readLedger(file, readFile4) {
@@ -8217,9 +8655,9 @@ var code_runner_daemon_exports = {};
8217
8655
  __export(code_runner_daemon_exports, {
8218
8656
  main: () => main
8219
8657
  });
8220
- import os3 from "node:os";
8658
+ import os4 from "node:os";
8221
8659
  import { randomUUID as randomUUID2 } from "node:crypto";
8222
- import { fileURLToPath as fileURLToPath3 } from "node:url";
8660
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
8223
8661
  function log2(msg) {
8224
8662
  console.log(`[code-runner ${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}`);
8225
8663
  }
@@ -8227,7 +8665,7 @@ function loadConfig(env2 = process.env) {
8227
8665
  const servedOperators = parseList(env2.VO_CODE_RUNNER_OPERATOR_IDS);
8228
8666
  const allowAmbientGithub = env2.VO_CODE_RUNNER_ALLOW_AMBIENT_GH === "1";
8229
8667
  return {
8230
- runnerId: env2.VO_CODE_RUNNER_ID || `vo-code-runner-${os3.hostname()}`,
8668
+ runnerId: env2.VO_CODE_RUNNER_ID || `vo-code-runner-${os4.hostname()}`,
8231
8669
  // BYO multi-agent: {agent, runner, runnerBin} — VO_CODE_RUNNER_AGENT selects the provider.
8232
8670
  ...resolveRunner(env2, { warn: (m) => log2(`agent-select: ${m}`) }),
8233
8671
  permissionMode: env2.VO_CODE_RUNNER_PERMISSION_MODE || "acceptEdits",
@@ -8240,7 +8678,7 @@ function loadConfig(env2 = process.env) {
8240
8678
  // 'Sees ALL agents': how often to forward the local session spool to the
8241
8679
  // cloud (best-effort). Default 30s. Set 0 to disable forwarding.
8242
8680
  sessionForwardSec: Math.max(0, Number(env2.VO_SESSION_FORWARD_SEC ?? 30) || 0),
8243
- operatorSeed: env2.VO_LOCAL_OPERATOR_SEED || env2.VO_CODE_RUNNER_ID || `local-${os3.hostname()}`,
8681
+ operatorSeed: env2.VO_LOCAL_OPERATOR_SEED || env2.VO_CODE_RUNNER_ID || `local-${os4.hostname()}`,
8244
8682
  cancelPollMs: Math.max(1e3, Number(env2.VO_CODE_RUNNER_CANCEL_POLL_MS || 2500) || 2500),
8245
8683
  // Hard cap OFF by default (0=no timer; work preserved via #7218 draft-PR). Set ms>0 to enforce; invalid→0.
8246
8684
  maxWallClockMs: ((n) => Number.isFinite(n) && n >= 0 ? n : 0)(Number(env2.VO_CODE_RUNNER_MAX_WALL_CLOCK_MS ?? NaN)),
@@ -8438,6 +8876,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
8438
8876
  await sweepStaleTaskAttachmentDirectories().catch((error) => log2(`stale attachment cleanup failed: ${error.message}`));
8439
8877
  const client = createControlPlaneClient({ env: env2 });
8440
8878
  const runnerInstanceId = randomUUID2();
8879
+ bootstrapOrphanReaper({ instanceId: runnerInstanceId, log: log2 });
8441
8880
  let reconcileStale = true;
8442
8881
  let stopping = false;
8443
8882
  let active = 0;
@@ -8550,6 +8989,7 @@ var init_code_runner_daemon = __esm({
8550
8989
  init_resolve_runner();
8551
8990
  init_rate_limit_resume();
8552
8991
  init_publish();
8992
+ init_orphan_agent_reaper();
8553
8993
  init_publish_async();
8554
8994
  init_resume_branch();
8555
8995
  init_task_prompt();
@@ -8575,7 +9015,7 @@ var init_code_runner_daemon = __esm({
8575
9015
  sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
8576
9016
  numOrUndef = (x) => typeof x === "number" ? x : void 0;
8577
9017
  safeProgress = makeSafeProgress(log2);
8578
- invokedDirectly = process.argv[1] && fileURLToPath3(import.meta.url) === process.argv[1] && // Bundle-safe: self-start only when THIS file is the real entry (not inlined into vo-mcp's runner-cli.js ⇒ double-claim).
9018
+ invokedDirectly = process.argv[1] && fileURLToPath4(import.meta.url) === process.argv[1] && // Bundle-safe: self-start only when THIS file is the real entry (not inlined into vo-mcp's runner-cli.js ⇒ double-claim).
8579
9019
  import.meta.url.endsWith("code-runner-daemon.mjs");
8580
9020
  if (invokedDirectly) {
8581
9021
  const once2 = process.argv.includes("--once");