@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.
- package/dist/cli.js +151 -58
- package/dist/cli.js.map +4 -4
- package/dist/index.js +146 -54
- package/dist/index.js.map +4 -4
- package/dist/runner-cli.js +758 -318
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +258 -38
- package/dist/runner-supervisor.js.map +4 -4
- package/package.json +1 -1
package/dist/runner-cli.js
CHANGED
|
@@ -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
|
|
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
|
|
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,
|
|
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}${
|
|
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 ${
|
|
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
|
|
2282
|
-
const res = await req("GET",
|
|
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 = [
|
|
2796
|
-
network = "
|
|
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,
|
|
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
|
-
|
|
3318
|
-
|
|
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 =
|
|
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", "
|
|
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 =
|
|
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
|
|
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 } =
|
|
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
|
-
|
|
3669
|
-
|
|
3670
|
-
"
|
|
3671
|
-
|
|
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
|
|
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:
|
|
3747
|
-
authenticated:
|
|
3748
|
-
message:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
3891
|
-
authenticated:
|
|
3892
|
-
message:
|
|
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
|
|
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
|
-
|
|
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
|
|
4165
|
-
import
|
|
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
|
|
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
|
|
4213
|
-
if (
|
|
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(
|
|
4219
|
-
const p = String(
|
|
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
|
|
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 =
|
|
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
|
|
5064
|
-
import
|
|
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 =
|
|
5075
|
-
const resolvedRoot =
|
|
5076
|
-
if (
|
|
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 =
|
|
5292
|
+
const root = path13.resolve(tempRoot);
|
|
5083
5293
|
await mkdir(root, { recursive: true });
|
|
5084
|
-
const directory = await mkdtemp(
|
|
5085
|
-
const marker = JSON.stringify({ owner: MARKER_OWNER, token: randomUUID(), directory:
|
|
5086
|
-
await writeFile(
|
|
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(
|
|
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 =
|
|
5317
|
+
tempRoot = os2.tmpdir(),
|
|
5108
5318
|
now = Date.now(),
|
|
5109
5319
|
maxAgeMs = DEFAULT_STALE_AGE_MS
|
|
5110
5320
|
} = {}) {
|
|
5111
|
-
const root =
|
|
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(
|
|
5121
|
-
const markerRaw = await readFile(
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
|
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(
|
|
5432
|
+
const record = JSON.parse(await readFile2(join4(spoolDir, f), "utf8"));
|
|
5223
5433
|
if (record && typeof record.session_key === "string") {
|
|
5224
|
-
out.push({ full:
|
|
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(
|
|
5441
|
+
async function readCloudMap(path18) {
|
|
5232
5442
|
try {
|
|
5233
|
-
return JSON.parse(await readFile2(
|
|
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 =
|
|
5307
|
-
CLOUD_MAP_FILE =
|
|
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
|
|
5377
|
-
import { dirname as
|
|
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 (!
|
|
5383
|
-
const content =
|
|
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
|
-
|
|
5606
|
+
mkdirSync4(dirname4(queuePath), { recursive: true });
|
|
5397
5607
|
const lines = entries.map((e) => JSON.stringify(e)).join("\n");
|
|
5398
|
-
|
|
5608
|
+
writeFileSync3(queuePath, lines + (entries.length > 0 ? "\n" : ""), "utf-8");
|
|
5399
5609
|
}
|
|
5400
5610
|
function attemptsStorePath() {
|
|
5401
|
-
return
|
|
5611
|
+
return join5(dirname4(resumeQueuePath()), "resume-attempts.json");
|
|
5402
5612
|
}
|
|
5403
5613
|
function readAttemptsStore() {
|
|
5404
5614
|
const p = attemptsStorePath();
|
|
5405
|
-
if (!
|
|
5615
|
+
if (!existsSync5(p)) return {};
|
|
5406
5616
|
try {
|
|
5407
|
-
const parsed = JSON.parse(
|
|
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
|
-
|
|
5416
|
-
|
|
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
|
|
5801
|
-
import
|
|
5802
|
-
function readClaudeUsage({ homeDir =
|
|
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(
|
|
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(
|
|
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
|
|
6186
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
5977
6187
|
function runGh(args) {
|
|
5978
|
-
const result =
|
|
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
|
|
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
|
|
6353
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
6144
6354
|
function ghViewPr(prNumber, repo) {
|
|
6145
|
-
const r =
|
|
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(
|
|
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 =
|
|
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
|
|
6767
|
+
const path18 = String(req.url || "").split("?")[0];
|
|
6558
6768
|
res.setHeader("content-type", "application/json");
|
|
6559
|
-
if (req.method === "GET" &&
|
|
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" &&
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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(
|
|
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 =
|
|
6910
|
-
ROOT =
|
|
6911
|
-
DEFAULT_CACHE_DIR =
|
|
6912
|
-
DEFAULT_CACHE_FILE =
|
|
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
|
|
7700
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
7454
7701
|
import { homedir as homedir5 } from "node:os";
|
|
7455
|
-
import { join as
|
|
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:
|
|
7727
|
+
function readCodexModelsCache({ path: path18 = DEFAULT_CODEX_MODELS_CACHE, read = readFileSync5 } = {}) {
|
|
7481
7728
|
try {
|
|
7482
|
-
const parsed = JSON.parse(read(
|
|
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 =
|
|
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
|
|
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
|
|
7540
|
-
import { fileURLToPath as
|
|
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 =
|
|
7548
|
-
cachedThresholds = JSON.parse(
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 { ...
|
|
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
|
|
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 =
|
|
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 =
|
|
7943
|
-
|
|
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(
|
|
8387
|
+
await fsp9.writeFile(path16.join(quarantineDir, "tracked.patch"), patch, "utf8");
|
|
7950
8388
|
for (const relative of paths.untracked) {
|
|
7951
|
-
const source =
|
|
7952
|
-
const target =
|
|
7953
|
-
await fsp9.mkdir(
|
|
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(
|
|
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 =
|
|
7979
|
-
const prefix = `${
|
|
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) =>
|
|
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
|
|
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 =
|
|
8477
|
+
const canonical = path17.join(clonesRoot2, leaf);
|
|
8040
8478
|
return [
|
|
8041
|
-
|
|
8042
|
-
|
|
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
|
|
8658
|
+
import os4 from "node:os";
|
|
8221
8659
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
8222
|
-
import { fileURLToPath as
|
|
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-${
|
|
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-${
|
|
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] &&
|
|
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");
|