@algosuite/vo-mcp 0.2.0-beta.16 → 0.2.0-beta.17
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 +5 -51
- package/dist/cli.js.map +2 -2
- package/dist/index.js +5 -51
- package/dist/index.js.map +2 -2
- package/dist/runner-cli.js +433 -290
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +238 -36
- 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,243 @@ 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
|
+
|
|
2953
3190
|
// ../../scripts/virtual-office/code-runner/claude-runner.mjs
|
|
2954
3191
|
import { spawn as spawn2 } from "node:child_process";
|
|
2955
3192
|
function extractText(content) {
|
|
@@ -3040,6 +3277,7 @@ function runAgentTask({
|
|
|
3040
3277
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3041
3278
|
...spawnOpts
|
|
3042
3279
|
});
|
|
3280
|
+
recordAgentPid({ pid: child.pid, agentId: spawnBin });
|
|
3043
3281
|
try {
|
|
3044
3282
|
child.stdin.write(String(prompt));
|
|
3045
3283
|
child.stdin.end();
|
|
@@ -3155,6 +3393,7 @@ function runAgentTask({
|
|
|
3155
3393
|
exitDrainTimer = setTimeout(() => finalizeChild({ code, signal }), exitDrainGraceMs);
|
|
3156
3394
|
});
|
|
3157
3395
|
child.on("close", (code, signal) => {
|
|
3396
|
+
unrecordAgentPid({ pid: child.pid });
|
|
3158
3397
|
finalizeChild({ code, signal });
|
|
3159
3398
|
});
|
|
3160
3399
|
});
|
|
@@ -3169,6 +3408,7 @@ var init_claude_runner = __esm({
|
|
|
3169
3408
|
init_claude_args();
|
|
3170
3409
|
init_windows_claude_launch();
|
|
3171
3410
|
init_terminal_process_cleanup();
|
|
3411
|
+
init_orphan_agent_reaper();
|
|
3172
3412
|
ClaudeRunner = class {
|
|
3173
3413
|
get binary() {
|
|
3174
3414
|
return "claude";
|
|
@@ -3314,17 +3554,8 @@ var init_agent_key_store = __esm({
|
|
|
3314
3554
|
});
|
|
3315
3555
|
|
|
3316
3556
|
// ../../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";
|
|
3557
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
3558
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
3328
3559
|
import { win32 } from "node:path";
|
|
3329
3560
|
function isTruthyFlag2(value) {
|
|
3330
3561
|
return ["1", "true", "yes", "on"].includes(String(value ?? "").trim().toLowerCase());
|
|
@@ -3332,7 +3563,7 @@ function isTruthyFlag2(value) {
|
|
|
3332
3563
|
function resolveCodexBinary({
|
|
3333
3564
|
env: env2 = process.env,
|
|
3334
3565
|
platform = process.platform,
|
|
3335
|
-
exists =
|
|
3566
|
+
exists = existsSync4
|
|
3336
3567
|
} = {}) {
|
|
3337
3568
|
if (platform !== "win32") return "codex";
|
|
3338
3569
|
const appData = String(env2.APPDATA || "").trim();
|
|
@@ -3367,7 +3598,7 @@ function resolveCodexBinary({
|
|
|
3367
3598
|
return "codex";
|
|
3368
3599
|
}
|
|
3369
3600
|
function buildCodexArgs({ model, effort } = {}) {
|
|
3370
|
-
const args = ["exec", "--json", "-c", 'approval_policy="never"', "--sandbox", "
|
|
3601
|
+
const args = ["exec", "--json", "-c", 'approval_policy="never"', "--sandbox", "workspace-write"];
|
|
3371
3602
|
if (model) {
|
|
3372
3603
|
args.push("--model", String(model));
|
|
3373
3604
|
}
|
|
@@ -3422,7 +3653,7 @@ var init_codex_runner = __esm({
|
|
|
3422
3653
|
CODEX_PREFER_LOGIN_ENV = "VO_RUNNER_CODEX_PREFER_LOGIN";
|
|
3423
3654
|
LEGACY_PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
|
|
3424
3655
|
CodexRunner = class {
|
|
3425
|
-
constructor({ spawn: spawn5 =
|
|
3656
|
+
constructor({ spawn: spawn5 = spawnSync6, resolveBinary = resolveCodexBinary, env: env2 = process.env } = {}) {
|
|
3426
3657
|
this.spawn = spawn5;
|
|
3427
3658
|
this.resolveBinary = resolveBinary;
|
|
3428
3659
|
this.env = env2;
|
|
@@ -3512,7 +3743,7 @@ ${login.stderr || ""}`.trim();
|
|
|
3512
3743
|
});
|
|
3513
3744
|
|
|
3514
3745
|
// ../../scripts/virtual-office/code-runner/cursor-runner.mjs
|
|
3515
|
-
import { spawnSync as
|
|
3746
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
3516
3747
|
function buildCursorArgs({ model, prompt } = {}) {
|
|
3517
3748
|
const args = ["-p", "--output-format", "stream-json", "--force"];
|
|
3518
3749
|
if (model) {
|
|
@@ -3591,7 +3822,7 @@ var init_cursor_runner = __esm({
|
|
|
3591
3822
|
/** Best-effort: is `cursor-agent` on PATH? Never throws. */
|
|
3592
3823
|
async checkAuth() {
|
|
3593
3824
|
try {
|
|
3594
|
-
const { status, error } =
|
|
3825
|
+
const { status, error } = spawnSync7("cursor-agent", ["--version"], {
|
|
3595
3826
|
shell: process.platform === "win32",
|
|
3596
3827
|
windowsHide: true,
|
|
3597
3828
|
timeout: 3e3,
|
|
@@ -3617,45 +3848,6 @@ var init_cursor_runner = __esm({
|
|
|
3617
3848
|
}
|
|
3618
3849
|
});
|
|
3619
3850
|
|
|
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
3851
|
// ../../scripts/virtual-office/code-runner/meta-runner.mjs
|
|
3660
3852
|
function applyMetaAuthEnv(baseEnv = process.env) {
|
|
3661
3853
|
const out = withAgentKey("meta", baseEnv);
|
|
@@ -3665,44 +3857,17 @@ function applyMetaAuthEnv(baseEnv = process.env) {
|
|
|
3665
3857
|
return out;
|
|
3666
3858
|
}
|
|
3667
3859
|
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;
|
|
3860
|
+
void opts;
|
|
3861
|
+
throw new Error(
|
|
3862
|
+
"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."
|
|
3863
|
+
);
|
|
3697
3864
|
}
|
|
3698
|
-
var
|
|
3865
|
+
var META_API_KEY_ENV, META_API_KEY_ALIAS, MetaRunner, metaRunner;
|
|
3699
3866
|
var init_meta_runner = __esm({
|
|
3700
3867
|
"../../scripts/virtual-office/code-runner/meta-runner.mjs"() {
|
|
3701
3868
|
"use strict";
|
|
3702
3869
|
init_codex_runner();
|
|
3703
3870
|
init_agent_key_store();
|
|
3704
|
-
init_meta_model_catalog();
|
|
3705
|
-
PROVIDER_SLUG = "meta";
|
|
3706
3871
|
META_API_KEY_ENV = "MODEL_API_KEY";
|
|
3707
3872
|
META_API_KEY_ALIAS = "META_API";
|
|
3708
3873
|
MetaRunner = class {
|
|
@@ -3731,21 +3896,10 @@ var init_meta_runner = __esm({
|
|
|
3731
3896
|
return `meta muse-spark key=${hasKey ? "set" : "MISSING"} transport=codex`;
|
|
3732
3897
|
}
|
|
3733
3898
|
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
3899
|
return {
|
|
3746
|
-
installed:
|
|
3747
|
-
authenticated:
|
|
3748
|
-
message:
|
|
3900
|
+
installed: false,
|
|
3901
|
+
authenticated: false,
|
|
3902
|
+
message: "Muse Spark coding is disabled; sanitized Model Firewall review only"
|
|
3749
3903
|
};
|
|
3750
3904
|
}
|
|
3751
3905
|
};
|
|
@@ -3757,91 +3911,23 @@ var init_meta_runner = __esm({
|
|
|
3757
3911
|
function resolveOaiBaseUrl(env2 = process.env) {
|
|
3758
3912
|
return String(env2.VO_CODE_RUNNER_OAI_BASE_URL || "").trim();
|
|
3759
3913
|
}
|
|
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;
|
|
3914
|
+
var OAI_API_KEY_ENV, OpenAICompatibleRunner, openaiCompatibleRunner;
|
|
3829
3915
|
var init_openai_compatible_runner = __esm({
|
|
3830
3916
|
"../../scripts/virtual-office/code-runner/openai-compatible-runner.mjs"() {
|
|
3831
3917
|
"use strict";
|
|
3832
3918
|
init_codex_runner();
|
|
3833
3919
|
init_agent_key_store();
|
|
3834
|
-
PROVIDER_SLUG2 = "vooai";
|
|
3835
3920
|
OAI_API_KEY_ENV = "VO_CODE_RUNNER_OAI_API_KEY";
|
|
3836
|
-
DEFAULT_OAI_MODEL = "deepseek/deepseek-chat";
|
|
3837
|
-
DEFAULT_OAI_WIRE_API = "responses";
|
|
3838
3921
|
OpenAICompatibleRunner = class {
|
|
3839
3922
|
/** Codex is the transport binary. */
|
|
3840
3923
|
get binary() {
|
|
3841
3924
|
return resolveCodexBinary();
|
|
3842
3925
|
}
|
|
3843
3926
|
buildArgs(opts = {}) {
|
|
3844
|
-
|
|
3927
|
+
void opts;
|
|
3928
|
+
throw new Error(
|
|
3929
|
+
"OpenAI-compatible full-repository coding is disabled. Use an explicit sanitized task capsule through the AlgoSuite Model Firewall."
|
|
3930
|
+
);
|
|
3845
3931
|
}
|
|
3846
3932
|
/** Codex JSONL events map identically → reuse the proven parser. */
|
|
3847
3933
|
parseEvent(line) {
|
|
@@ -3865,31 +3951,10 @@ var init_openai_compatible_runner = __esm({
|
|
|
3865
3951
|
}
|
|
3866
3952
|
/** Best-effort: base URL chosen AND the codex transport is installed. */
|
|
3867
3953
|
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
3954
|
return {
|
|
3890
|
-
installed:
|
|
3891
|
-
authenticated:
|
|
3892
|
-
message:
|
|
3955
|
+
installed: false,
|
|
3956
|
+
authenticated: false,
|
|
3957
|
+
message: "OpenAI-compatible coding is disabled; sanitized Model Firewall task capsules only"
|
|
3893
3958
|
};
|
|
3894
3959
|
}
|
|
3895
3960
|
};
|
|
@@ -4046,7 +4111,7 @@ var init_rate_limit_detector_core = __esm({
|
|
|
4046
4111
|
});
|
|
4047
4112
|
|
|
4048
4113
|
// ../../scripts/virtual-office/code-runner/rate-limit-resume.mjs
|
|
4049
|
-
import { appendFileSync, mkdirSync as
|
|
4114
|
+
import { appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
|
|
4050
4115
|
import { homedir as homedir2 } from "node:os";
|
|
4051
4116
|
import { join as join2, dirname as dirname2 } from "node:path";
|
|
4052
4117
|
function resumeQueuePath() {
|
|
@@ -4069,7 +4134,7 @@ function buildResumeEntry({ task = {}, resumeAfter = null, summary = "", at } =
|
|
|
4069
4134
|
function recordRateLimited({ task = {}, resumeAfter = null, summary = "", queuePath = resumeQueuePath(), at = (/* @__PURE__ */ new Date()).toISOString() } = {}) {
|
|
4070
4135
|
const entry = buildResumeEntry({ task, resumeAfter, summary, at });
|
|
4071
4136
|
try {
|
|
4072
|
-
|
|
4137
|
+
mkdirSync3(dirname2(queuePath), { recursive: true });
|
|
4073
4138
|
appendFileSync(queuePath, `${JSON.stringify(entry)}
|
|
4074
4139
|
`, "utf-8");
|
|
4075
4140
|
return { ok: true, entry };
|
|
@@ -4161,8 +4226,8 @@ var init_auto_merge = __esm({
|
|
|
4161
4226
|
});
|
|
4162
4227
|
|
|
4163
4228
|
// ../../scripts/virtual-office/code-runner/pr-overlap-gate.mjs
|
|
4164
|
-
import { spawnSync as
|
|
4165
|
-
import
|
|
4229
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
4230
|
+
import path11 from "node:path";
|
|
4166
4231
|
var init_pr_overlap_gate = __esm({
|
|
4167
4232
|
"../../scripts/virtual-office/code-runner/pr-overlap-gate.mjs"() {
|
|
4168
4233
|
"use strict";
|
|
@@ -4202,21 +4267,21 @@ var init_existing_pr_publication = __esm({
|
|
|
4202
4267
|
});
|
|
4203
4268
|
|
|
4204
4269
|
// ../../scripts/virtual-office/code-runner/publish.mjs
|
|
4205
|
-
import { spawnSync as
|
|
4270
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
4206
4271
|
function parsePorcelainZ(out) {
|
|
4207
4272
|
const tokens = String(out).split("\0");
|
|
4208
4273
|
const files = [];
|
|
4209
4274
|
for (let i = 0; i < tokens.length; i += 1) {
|
|
4210
4275
|
const tok = tokens[i];
|
|
4211
4276
|
if (!tok) continue;
|
|
4212
|
-
const
|
|
4213
|
-
if (
|
|
4277
|
+
const path18 = tok.slice(3);
|
|
4278
|
+
if (path18) files.push(path18);
|
|
4214
4279
|
if (tok[0] === "R" || tok[0] === "C") i += 1;
|
|
4215
4280
|
}
|
|
4216
4281
|
return files;
|
|
4217
4282
|
}
|
|
4218
|
-
function isAgentScratch(
|
|
4219
|
-
const p = String(
|
|
4283
|
+
function isAgentScratch(path18) {
|
|
4284
|
+
const p = String(path18 || "");
|
|
4220
4285
|
return SCRATCH_PATTERNS.some((re) => re.test(p));
|
|
4221
4286
|
}
|
|
4222
4287
|
function isMaxTurnsResult(summary) {
|
|
@@ -4423,7 +4488,7 @@ var init_partial_pr_continuation = __esm({
|
|
|
4423
4488
|
});
|
|
4424
4489
|
|
|
4425
4490
|
// ../../scripts/virtual-office/code-runner/publish-async.mjs
|
|
4426
|
-
import
|
|
4491
|
+
import path12 from "node:path";
|
|
4427
4492
|
function compactTitle(value, max = 100) {
|
|
4428
4493
|
return String(value || "").replace(/\s+/g, " ").trim().slice(0, max) || "code-task";
|
|
4429
4494
|
}
|
|
@@ -4465,7 +4530,7 @@ async function resolveOrCreateBranchAsync(worktreeDir, branchPrefix, runCommand
|
|
|
4465
4530
|
return branch;
|
|
4466
4531
|
}
|
|
4467
4532
|
async function runLocalPrOverlapGateAsync(worktreeDir, files, { branch = "", env: env2 = process.env, excludePrNumber = null } = {}) {
|
|
4468
|
-
const scriptPath =
|
|
4533
|
+
const scriptPath = path12.join(worktreeDir, "scripts", "ci", "check-local-pr-overlap.mjs");
|
|
4469
4534
|
try {
|
|
4470
4535
|
const output = await runProcess2("node", [
|
|
4471
4536
|
scriptPath,
|
|
@@ -5060,8 +5125,8 @@ var init_task_prompt = __esm({
|
|
|
5060
5125
|
// ../../scripts/virtual-office/code-runner/task-attachments.mjs
|
|
5061
5126
|
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
5062
5127
|
import { chmod, mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
5063
|
-
import
|
|
5064
|
-
import
|
|
5128
|
+
import os2 from "node:os";
|
|
5129
|
+
import path13 from "node:path";
|
|
5065
5130
|
function safeTaskToken(taskId) {
|
|
5066
5131
|
return String(taskId || "task").replace(/[^0-9A-Za-z_-]/gu, "_").slice(0, 48) || "task";
|
|
5067
5132
|
}
|
|
@@ -5071,25 +5136,25 @@ function sanitizeTaskAttachmentName(name, index = 0) {
|
|
|
5071
5136
|
return `${String(index + 1).padStart(2, "0")}-${normalized}`;
|
|
5072
5137
|
}
|
|
5073
5138
|
function assertGeneratedDirectory(directory, tempRoot) {
|
|
5074
|
-
const resolvedDirectory =
|
|
5075
|
-
const resolvedRoot =
|
|
5076
|
-
if (
|
|
5139
|
+
const resolvedDirectory = path13.resolve(directory);
|
|
5140
|
+
const resolvedRoot = path13.resolve(tempRoot);
|
|
5141
|
+
if (path13.dirname(resolvedDirectory) !== resolvedRoot || !path13.basename(resolvedDirectory).startsWith(DIRECTORY_PREFIX)) {
|
|
5077
5142
|
throw new Error("refusing to clean an unverified task-attachment directory");
|
|
5078
5143
|
}
|
|
5079
5144
|
return resolvedDirectory;
|
|
5080
5145
|
}
|
|
5081
5146
|
async function createAttachmentDirectory(taskId, tempRoot) {
|
|
5082
|
-
const root =
|
|
5147
|
+
const root = path13.resolve(tempRoot);
|
|
5083
5148
|
await mkdir(root, { recursive: true });
|
|
5084
|
-
const directory = await mkdtemp(
|
|
5085
|
-
const marker = JSON.stringify({ owner: MARKER_OWNER, token: randomUUID(), directory:
|
|
5086
|
-
await writeFile(
|
|
5149
|
+
const directory = await mkdtemp(path13.join(root, `${DIRECTORY_PREFIX}${safeTaskToken(taskId)}-`));
|
|
5150
|
+
const marker = JSON.stringify({ owner: MARKER_OWNER, token: randomUUID(), directory: path13.basename(directory), created_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
5151
|
+
await writeFile(path13.join(directory, MARKER_FILE), marker, { encoding: "utf8", mode: 384 });
|
|
5087
5152
|
return { directory, marker, tempRoot: root };
|
|
5088
5153
|
}
|
|
5089
5154
|
async function cleanupGeneratedDirectory(state) {
|
|
5090
5155
|
if (!state || state.cleaned) return;
|
|
5091
5156
|
const directory = assertGeneratedDirectory(state.directory, state.tempRoot);
|
|
5092
|
-
const marker = await readFile(
|
|
5157
|
+
const marker = await readFile(path13.join(directory, MARKER_FILE), "utf8").catch(() => "");
|
|
5093
5158
|
if (marker !== state.marker) throw new Error("refusing to clean a task-attachment directory without its exact marker");
|
|
5094
5159
|
await rm(directory, { recursive: true, force: true });
|
|
5095
5160
|
state.cleaned = true;
|
|
@@ -5104,11 +5169,11 @@ function parseOwnedMarker(raw, directoryName) {
|
|
|
5104
5169
|
}
|
|
5105
5170
|
}
|
|
5106
5171
|
async function sweepStaleTaskAttachmentDirectories({
|
|
5107
|
-
tempRoot =
|
|
5172
|
+
tempRoot = os2.tmpdir(),
|
|
5108
5173
|
now = Date.now(),
|
|
5109
5174
|
maxAgeMs = DEFAULT_STALE_AGE_MS
|
|
5110
5175
|
} = {}) {
|
|
5111
|
-
const root =
|
|
5176
|
+
const root = path13.resolve(tempRoot);
|
|
5112
5177
|
if (!Number.isFinite(maxAgeMs) || maxAgeMs <= 0) throw new Error("stale attachment age must be positive");
|
|
5113
5178
|
const entries = await readdir(root, { withFileTypes: true }).catch((error) => {
|
|
5114
5179
|
if (error?.code === "ENOENT") return [];
|
|
@@ -5117,8 +5182,8 @@ async function sweepStaleTaskAttachmentDirectories({
|
|
|
5117
5182
|
let removed = 0;
|
|
5118
5183
|
for (const entry of entries) {
|
|
5119
5184
|
if (!entry.isDirectory() || !entry.name.startsWith(DIRECTORY_PREFIX)) continue;
|
|
5120
|
-
const directory = assertGeneratedDirectory(
|
|
5121
|
-
const markerRaw = await readFile(
|
|
5185
|
+
const directory = assertGeneratedDirectory(path13.join(root, entry.name), root);
|
|
5186
|
+
const markerRaw = await readFile(path13.join(directory, MARKER_FILE), "utf8").catch(() => "");
|
|
5122
5187
|
const marker = parseOwnedMarker(markerRaw, entry.name);
|
|
5123
5188
|
if (!marker) continue;
|
|
5124
5189
|
const directoryStat = await stat(directory);
|
|
@@ -5145,7 +5210,7 @@ function buildManifest(files) {
|
|
|
5145
5210
|
"\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
5211
|
].join("\n");
|
|
5147
5212
|
}
|
|
5148
|
-
async function materializeTaskAttachments(client, task, { tempRoot =
|
|
5213
|
+
async function materializeTaskAttachments(client, task, { tempRoot = os2.tmpdir() } = {}) {
|
|
5149
5214
|
const refs = Array.isArray(task?.attachments) ? task.attachments : [];
|
|
5150
5215
|
if (refs.length === 0) return { directory: null, files: [], manifestMarkdown: "", cleanup: async () => {
|
|
5151
5216
|
} };
|
|
@@ -5161,10 +5226,10 @@ async function materializeTaskAttachments(client, task, { tempRoot = os.tmpdir()
|
|
|
5161
5226
|
const sha256 = createHash3("sha256").update(content).digest("hex");
|
|
5162
5227
|
if (sha256 !== ref.sha256) throw new Error(`attachment ${ref.attachment_id} sha256 mismatch`);
|
|
5163
5228
|
const name = sanitizeTaskAttachmentName(ref.name, index);
|
|
5164
|
-
const filePath =
|
|
5229
|
+
const filePath = path13.join(state.directory, name);
|
|
5165
5230
|
await writeFile(filePath, content, { flag: "wx", mode: 384 });
|
|
5166
5231
|
await chmod(filePath, 384);
|
|
5167
|
-
files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path:
|
|
5232
|
+
files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path: path13.resolve(filePath) });
|
|
5168
5233
|
}
|
|
5169
5234
|
return { directory: state.directory, files, manifestMarkdown: buildManifest(files), cleanup: () => cleanupGeneratedDirectory(state) };
|
|
5170
5235
|
} catch (error) {
|
|
@@ -5228,9 +5293,9 @@ async function readSpool(spoolDir = SPOOL_DIR) {
|
|
|
5228
5293
|
}
|
|
5229
5294
|
return out;
|
|
5230
5295
|
}
|
|
5231
|
-
async function readCloudMap(
|
|
5296
|
+
async function readCloudMap(path18) {
|
|
5232
5297
|
try {
|
|
5233
|
-
return JSON.parse(await readFile2(
|
|
5298
|
+
return JSON.parse(await readFile2(path18, "utf8"));
|
|
5234
5299
|
} catch {
|
|
5235
5300
|
return {};
|
|
5236
5301
|
}
|
|
@@ -5373,14 +5438,14 @@ var init_rate_limit_resume_scheduler_core = __esm({
|
|
|
5373
5438
|
});
|
|
5374
5439
|
|
|
5375
5440
|
// ../../scripts/virtual-office/code-runner/rate-limit-resume-scheduler.mjs
|
|
5376
|
-
import { readFileSync as
|
|
5441
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "node:fs";
|
|
5377
5442
|
import { dirname as dirname3, join as join4, resolve } from "node:path";
|
|
5378
5443
|
function log(msg) {
|
|
5379
5444
|
console.log(`[rate-limit-scheduler ${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}`);
|
|
5380
5445
|
}
|
|
5381
5446
|
function readQueue(queuePath) {
|
|
5382
|
-
if (!
|
|
5383
|
-
const content =
|
|
5447
|
+
if (!existsSync5(queuePath)) return [];
|
|
5448
|
+
const content = readFileSync3(queuePath, "utf-8");
|
|
5384
5449
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
5385
5450
|
const entries = [];
|
|
5386
5451
|
for (const line of lines) {
|
|
@@ -5393,18 +5458,18 @@ function readQueue(queuePath) {
|
|
|
5393
5458
|
return entries;
|
|
5394
5459
|
}
|
|
5395
5460
|
function writeQueue(queuePath, entries) {
|
|
5396
|
-
|
|
5461
|
+
mkdirSync4(dirname3(queuePath), { recursive: true });
|
|
5397
5462
|
const lines = entries.map((e) => JSON.stringify(e)).join("\n");
|
|
5398
|
-
|
|
5463
|
+
writeFileSync3(queuePath, lines + (entries.length > 0 ? "\n" : ""), "utf-8");
|
|
5399
5464
|
}
|
|
5400
5465
|
function attemptsStorePath() {
|
|
5401
5466
|
return join4(dirname3(resumeQueuePath()), "resume-attempts.json");
|
|
5402
5467
|
}
|
|
5403
5468
|
function readAttemptsStore() {
|
|
5404
5469
|
const p = attemptsStorePath();
|
|
5405
|
-
if (!
|
|
5470
|
+
if (!existsSync5(p)) return {};
|
|
5406
5471
|
try {
|
|
5407
|
-
const parsed = JSON.parse(
|
|
5472
|
+
const parsed = JSON.parse(readFileSync3(p, "utf-8"));
|
|
5408
5473
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
5409
5474
|
} catch {
|
|
5410
5475
|
return {};
|
|
@@ -5412,8 +5477,8 @@ function readAttemptsStore() {
|
|
|
5412
5477
|
}
|
|
5413
5478
|
function writeAttemptsStore(store) {
|
|
5414
5479
|
const p = attemptsStorePath();
|
|
5415
|
-
|
|
5416
|
-
|
|
5480
|
+
mkdirSync4(dirname3(p), { recursive: true });
|
|
5481
|
+
writeFileSync3(p, JSON.stringify(store, null, 2), "utf-8");
|
|
5417
5482
|
}
|
|
5418
5483
|
function countsFromStore(store) {
|
|
5419
5484
|
const counts = {};
|
|
@@ -5797,9 +5862,9 @@ var init_agent_availability = __esm({
|
|
|
5797
5862
|
// ../../scripts/virtual-office/code-runner/account-usage.mjs
|
|
5798
5863
|
import { spawn as spawn4 } from "node:child_process";
|
|
5799
5864
|
import fs6 from "node:fs";
|
|
5800
|
-
import
|
|
5801
|
-
import
|
|
5802
|
-
function readClaudeUsage({ homeDir =
|
|
5865
|
+
import os3 from "node:os";
|
|
5866
|
+
import path14 from "node:path";
|
|
5867
|
+
function readClaudeUsage({ homeDir = os3.homedir(), read: rawRead = readJson } = {}) {
|
|
5803
5868
|
const read = (p) => {
|
|
5804
5869
|
try {
|
|
5805
5870
|
return rawRead(p);
|
|
@@ -5807,7 +5872,7 @@ function readClaudeUsage({ homeDir = os2.homedir(), read: rawRead = readJson } =
|
|
|
5807
5872
|
return null;
|
|
5808
5873
|
}
|
|
5809
5874
|
};
|
|
5810
|
-
const status = read(
|
|
5875
|
+
const status = read(path14.join(homeDir, ".claude", "claude-usage.json"));
|
|
5811
5876
|
if (status && (status.seven_day || status.five_hour)) {
|
|
5812
5877
|
const entry = {
|
|
5813
5878
|
agent: "claude",
|
|
@@ -5816,7 +5881,7 @@ function readClaudeUsage({ homeDir = os2.homedir(), read: rawRead = readJson } =
|
|
|
5816
5881
|
};
|
|
5817
5882
|
if (entry.seven_day_used_pct !== null || entry.five_hour_used_pct !== null) return entry;
|
|
5818
5883
|
}
|
|
5819
|
-
const weekly = read(
|
|
5884
|
+
const weekly = read(path14.join(homeDir, ".claude", "claude-weekly-usage.json"));
|
|
5820
5885
|
if (weekly) {
|
|
5821
5886
|
const entry = {
|
|
5822
5887
|
agent: "claude",
|
|
@@ -5973,9 +6038,9 @@ var init_account_usage = __esm({
|
|
|
5973
6038
|
});
|
|
5974
6039
|
|
|
5975
6040
|
// ../../scripts/virtual-office/code-runner/ci-repair-evidence.mjs
|
|
5976
|
-
import { spawnSync as
|
|
6041
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
5977
6042
|
function runGh(args) {
|
|
5978
|
-
const result =
|
|
6043
|
+
const result = spawnSync10("gh", args, { encoding: "utf8", timeout: 6e4, windowsHide: true });
|
|
5979
6044
|
if (result.error) throw result.error;
|
|
5980
6045
|
if (result.status !== 0) throw new Error((result.stderr || `gh ${args[0]} failed`).slice(-500));
|
|
5981
6046
|
return result.stdout || "";
|
|
@@ -6140,9 +6205,9 @@ var init_superseded_pr_source = __esm({
|
|
|
6140
6205
|
import { homedir as homedir4 } from "node:os";
|
|
6141
6206
|
import { join as join5 } from "node:path";
|
|
6142
6207
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir2 } from "node:fs/promises";
|
|
6143
|
-
import { spawnSync as
|
|
6208
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
6144
6209
|
function ghViewPr(prNumber, repo) {
|
|
6145
|
-
const r =
|
|
6210
|
+
const r = spawnSync11(
|
|
6146
6211
|
"gh",
|
|
6147
6212
|
["pr", "view", String(prNumber), "-R", repo, "--json", "state,statusCheckRollup,headRefName,headRefOid,url,isDraft,mergeStateStatus"],
|
|
6148
6213
|
{ encoding: "utf8", timeout: 3e4 }
|
|
@@ -6554,9 +6619,9 @@ function buildControlHandler({ getStatus, requestStop, allowedOrigin }) {
|
|
|
6554
6619
|
res.end();
|
|
6555
6620
|
return;
|
|
6556
6621
|
}
|
|
6557
|
-
const
|
|
6622
|
+
const path18 = String(req.url || "").split("?")[0];
|
|
6558
6623
|
res.setHeader("content-type", "application/json");
|
|
6559
|
-
if (req.method === "GET" &&
|
|
6624
|
+
if (req.method === "GET" && path18 === "/status") {
|
|
6560
6625
|
let status;
|
|
6561
6626
|
try {
|
|
6562
6627
|
status = getStatus();
|
|
@@ -6567,7 +6632,7 @@ function buildControlHandler({ getStatus, requestStop, allowedOrigin }) {
|
|
|
6567
6632
|
res.end(JSON.stringify({ ok: true, ...status }));
|
|
6568
6633
|
return;
|
|
6569
6634
|
}
|
|
6570
|
-
if (req.method === "POST" &&
|
|
6635
|
+
if (req.method === "POST" && path18 === "/stop") {
|
|
6571
6636
|
if (!isControlOriginAllowed(req.headers.origin, allowedOrigin) || !req.headers["x-vo-control"]) {
|
|
6572
6637
|
res.statusCode = 403;
|
|
6573
6638
|
res.end(JSON.stringify({ ok: false, error: "forbidden" }));
|
|
@@ -6725,7 +6790,7 @@ var init_effort_mode_config = __esm({
|
|
|
6725
6790
|
|
|
6726
6791
|
// ../../scripts/virtual-office/model-registry.mjs
|
|
6727
6792
|
import fs7 from "node:fs";
|
|
6728
|
-
import
|
|
6793
|
+
import path15 from "node:path";
|
|
6729
6794
|
import { fileURLToPath } from "node:url";
|
|
6730
6795
|
function uniqueModels(models = []) {
|
|
6731
6796
|
return [...new Set(models.map((model) => String(model || "").trim()).filter(Boolean))];
|
|
@@ -6848,7 +6913,7 @@ function readCache(cacheFile = DEFAULT_CACHE_FILE, nowMs = Date.now(), ttlMs = D
|
|
|
6848
6913
|
}
|
|
6849
6914
|
}
|
|
6850
6915
|
function writeCache(cacheFile = DEFAULT_CACHE_FILE, payload) {
|
|
6851
|
-
fs7.mkdirSync(
|
|
6916
|
+
fs7.mkdirSync(path15.dirname(cacheFile), { recursive: true });
|
|
6852
6917
|
fs7.writeFileSync(cacheFile, JSON.stringify(payload, null, 2));
|
|
6853
6918
|
}
|
|
6854
6919
|
async function fetchRegistryCatalog({
|
|
@@ -6906,10 +6971,10 @@ var __dirname, ROOT, DEFAULT_CACHE_DIR, DEFAULT_CACHE_FILE, DEFAULT_TTL_MS3, ANT
|
|
|
6906
6971
|
var init_model_registry = __esm({
|
|
6907
6972
|
"../../scripts/virtual-office/model-registry.mjs"() {
|
|
6908
6973
|
"use strict";
|
|
6909
|
-
__dirname =
|
|
6910
|
-
ROOT =
|
|
6911
|
-
DEFAULT_CACHE_DIR =
|
|
6912
|
-
DEFAULT_CACHE_FILE =
|
|
6974
|
+
__dirname = path15.dirname(fileURLToPath(import.meta.url));
|
|
6975
|
+
ROOT = path15.resolve(__dirname, "..", "..");
|
|
6976
|
+
DEFAULT_CACHE_DIR = path15.join(ROOT, ".virtual-office-cache", "model-registry");
|
|
6977
|
+
DEFAULT_CACHE_FILE = path15.join(DEFAULT_CACHE_DIR, "catalog.json");
|
|
6913
6978
|
DEFAULT_TTL_MS3 = 60 * 60 * 1e3;
|
|
6914
6979
|
ANTHROPIC_API_VERSION = "2023-06-01";
|
|
6915
6980
|
FAMILY_DEFINITIONS = {
|
|
@@ -6969,6 +7034,42 @@ var init_model_registry = __esm({
|
|
|
6969
7034
|
}
|
|
6970
7035
|
});
|
|
6971
7036
|
|
|
7037
|
+
// ../../scripts/virtual-office/code-runner/meta-model-catalog.mjs
|
|
7038
|
+
function normalizeMetaEffort(value) {
|
|
7039
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
7040
|
+
if (["low", "medium", "high", "xhigh"].includes(normalized)) return normalized;
|
|
7041
|
+
if (normalized === "max") return "xhigh";
|
|
7042
|
+
return null;
|
|
7043
|
+
}
|
|
7044
|
+
function resolveMetaModelForTier() {
|
|
7045
|
+
return META_DEFAULT_MODEL;
|
|
7046
|
+
}
|
|
7047
|
+
function resolveMetaEffortForTier(tier = "mid") {
|
|
7048
|
+
return TIER_EFFORT[tier] || TIER_EFFORT.mid;
|
|
7049
|
+
}
|
|
7050
|
+
function resolveMetaEffortForRung(rung = "R3") {
|
|
7051
|
+
return RUNG_EFFORT[rung] || RUNG_EFFORT.R3;
|
|
7052
|
+
}
|
|
7053
|
+
var META_DEFAULT_MODEL, TIER_EFFORT, RUNG_EFFORT;
|
|
7054
|
+
var init_meta_model_catalog = __esm({
|
|
7055
|
+
"../../scripts/virtual-office/code-runner/meta-model-catalog.mjs"() {
|
|
7056
|
+
"use strict";
|
|
7057
|
+
META_DEFAULT_MODEL = "muse-spark-1.1";
|
|
7058
|
+
TIER_EFFORT = Object.freeze({
|
|
7059
|
+
cheap: "low",
|
|
7060
|
+
mid: "medium",
|
|
7061
|
+
best: "xhigh"
|
|
7062
|
+
});
|
|
7063
|
+
RUNG_EFFORT = Object.freeze({
|
|
7064
|
+
R1: "low",
|
|
7065
|
+
R2: "medium",
|
|
7066
|
+
R3: "medium",
|
|
7067
|
+
R4: "high",
|
|
7068
|
+
R5: "xhigh"
|
|
7069
|
+
});
|
|
7070
|
+
}
|
|
7071
|
+
});
|
|
7072
|
+
|
|
6972
7073
|
// ../../scripts/virtual-office/code-runner/model-router.mjs
|
|
6973
7074
|
function normalizeAgent(agent = DEFAULT_AGENT2) {
|
|
6974
7075
|
const normalized = String(agent || DEFAULT_AGENT2).trim().toLowerCase();
|
|
@@ -7450,7 +7551,7 @@ var init_classify_task = __esm({
|
|
|
7450
7551
|
});
|
|
7451
7552
|
|
|
7452
7553
|
// ../../scripts/virtual-office/code-runner/auto-router/effort-policy.mjs
|
|
7453
|
-
import { readFileSync as
|
|
7554
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
7454
7555
|
import { homedir as homedir5 } from "node:os";
|
|
7455
7556
|
import { join as join6 } from "node:path";
|
|
7456
7557
|
function difficultyToRung(difficulty, thresholds) {
|
|
@@ -7477,9 +7578,9 @@ function operatorTierToRung(tier, difficulty, thresholds) {
|
|
|
7477
7578
|
if (tier === "best" && difficulty >= thresholds.rungBounds.R5) return "R5";
|
|
7478
7579
|
return base;
|
|
7479
7580
|
}
|
|
7480
|
-
function readCodexModelsCache({ path:
|
|
7581
|
+
function readCodexModelsCache({ path: path18 = DEFAULT_CODEX_MODELS_CACHE, read = readFileSync4 } = {}) {
|
|
7481
7582
|
try {
|
|
7482
|
-
const parsed = JSON.parse(read(
|
|
7583
|
+
const parsed = JSON.parse(read(path18, "utf8"));
|
|
7483
7584
|
return Array.isArray(parsed?.models) ? parsed : null;
|
|
7484
7585
|
} catch {
|
|
7485
7586
|
return null;
|
|
@@ -7534,7 +7635,7 @@ var init_effort_policy = __esm({
|
|
|
7534
7635
|
});
|
|
7535
7636
|
|
|
7536
7637
|
// ../../scripts/virtual-office/code-runner/auto-router/auto-router.mjs
|
|
7537
|
-
import { readFileSync as
|
|
7638
|
+
import { readFileSync as readFileSync5, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
7538
7639
|
import { homedir as homedir6 } from "node:os";
|
|
7539
7640
|
import { join as join7, dirname as dirname4 } from "node:path";
|
|
7540
7641
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -7545,7 +7646,7 @@ function getAutoRouterMode(env2 = process.env) {
|
|
|
7545
7646
|
function loadThresholds() {
|
|
7546
7647
|
if (!cachedThresholds) {
|
|
7547
7648
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
7548
|
-
cachedThresholds = JSON.parse(
|
|
7649
|
+
cachedThresholds = JSON.parse(readFileSync5(join7(here, "thresholds.json"), "utf8"));
|
|
7549
7650
|
}
|
|
7550
7651
|
return cachedThresholds;
|
|
7551
7652
|
}
|
|
@@ -7865,26 +7966,66 @@ function safeIdentityPart(value, fallback) {
|
|
|
7865
7966
|
const normalized = String(value || "").trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
7866
7967
|
return normalized || fallback;
|
|
7867
7968
|
}
|
|
7969
|
+
function safeBaseEnv(env2 = {}) {
|
|
7970
|
+
const result = {};
|
|
7971
|
+
for (const [key, value] of Object.entries(env2)) {
|
|
7972
|
+
if (value !== void 0 && SAFE_ENV_NAMES.has(key.toUpperCase())) result[key] = value;
|
|
7973
|
+
}
|
|
7974
|
+
return result;
|
|
7975
|
+
}
|
|
7868
7976
|
function buildAgentProcessEnv(env2, { agent = "agent", runnerId = "vo-runner", taskId = "task" } = {}) {
|
|
7869
|
-
|
|
7977
|
+
const base = safeBaseEnv(env2);
|
|
7978
|
+
if (String(env2?.AGENT_ID || "").trim()) return { ...base, AGENT_ID: env2.AGENT_ID };
|
|
7870
7979
|
const generated = [
|
|
7871
7980
|
"vo",
|
|
7872
7981
|
safeIdentityPart(agent, "agent"),
|
|
7873
7982
|
safeIdentityPart(runnerId, "runner"),
|
|
7874
7983
|
safeIdentityPart(taskId, "task").slice(0, 12)
|
|
7875
7984
|
].join("-");
|
|
7876
|
-
return { ...
|
|
7985
|
+
return { ...base, AGENT_ID: generated };
|
|
7877
7986
|
}
|
|
7987
|
+
var SAFE_ENV_NAMES;
|
|
7878
7988
|
var init_agent_process_env = __esm({
|
|
7879
7989
|
"../../scripts/virtual-office/code-runner/agent-process-env.mjs"() {
|
|
7880
7990
|
"use strict";
|
|
7991
|
+
SAFE_ENV_NAMES = /* @__PURE__ */ new Set([
|
|
7992
|
+
"AGENT_ID",
|
|
7993
|
+
"APPDATA",
|
|
7994
|
+
"CI",
|
|
7995
|
+
"COLORTERM",
|
|
7996
|
+
"COMSPEC",
|
|
7997
|
+
"FORCE_COLOR",
|
|
7998
|
+
"HOME",
|
|
7999
|
+
"HOMEDRIVE",
|
|
8000
|
+
"HOMEPATH",
|
|
8001
|
+
"LANG",
|
|
8002
|
+
"LOCALAPPDATA",
|
|
8003
|
+
"LOGONSERVER",
|
|
8004
|
+
"NO_COLOR",
|
|
8005
|
+
"NUMBER_OF_PROCESSORS",
|
|
8006
|
+
"OS",
|
|
8007
|
+
"PATH",
|
|
8008
|
+
"PATHEXT",
|
|
8009
|
+
"PROCESSOR_ARCHITECTURE",
|
|
8010
|
+
"PROGRAMDATA",
|
|
8011
|
+
"SYSTEMDRIVE",
|
|
8012
|
+
"SYSTEMROOT",
|
|
8013
|
+
"TEMP",
|
|
8014
|
+
"TERM",
|
|
8015
|
+
"TMP",
|
|
8016
|
+
"TMPDIR",
|
|
8017
|
+
"USERDOMAIN",
|
|
8018
|
+
"USERNAME",
|
|
8019
|
+
"USERPROFILE",
|
|
8020
|
+
"WINDIR"
|
|
8021
|
+
]);
|
|
7881
8022
|
}
|
|
7882
8023
|
});
|
|
7883
8024
|
|
|
7884
8025
|
// ../../scripts/virtual-office/code-runner/isolation-audit.mjs
|
|
7885
8026
|
import fs8 from "node:fs";
|
|
7886
8027
|
import fsp9 from "node:fs/promises";
|
|
7887
|
-
import
|
|
8028
|
+
import path16 from "node:path";
|
|
7888
8029
|
async function defaultRun(command, args, cwd, options = {}) {
|
|
7889
8030
|
return runProcess2(command, args, { cwd, timeout: 6e4, ...options });
|
|
7890
8031
|
}
|
|
@@ -7897,7 +8038,7 @@ async function canonicalRootForWorktree(worktreeDir, run) {
|
|
|
7897
8038
|
"--path-format=absolute",
|
|
7898
8039
|
"--git-common-dir"
|
|
7899
8040
|
])).trim();
|
|
7900
|
-
const root =
|
|
8041
|
+
const root = path16.dirname(commonDir);
|
|
7901
8042
|
return samePath2(root, worktreeDir) ? null : root;
|
|
7902
8043
|
}
|
|
7903
8044
|
async function snapshot(root, run) {
|
|
@@ -7939,21 +8080,21 @@ async function changedPaths(root, run) {
|
|
|
7939
8080
|
}
|
|
7940
8081
|
async function quarantineCanonicalWrites({ baseline, worktreeDir, taskId, run, now }) {
|
|
7941
8082
|
const paths = await changedPaths(baseline.root, run);
|
|
7942
|
-
const quarantineDir =
|
|
7943
|
-
|
|
8083
|
+
const quarantineDir = path16.join(
|
|
8084
|
+
path16.dirname(worktreeDir),
|
|
7944
8085
|
".canonical-recovery",
|
|
7945
8086
|
`${String(taskId || "unknown").replace(/[^a-z0-9-]/gi, "-")}-${now().toISOString().replace(/[:.]/g, "-")}`
|
|
7946
8087
|
);
|
|
7947
8088
|
await fsp9.mkdir(quarantineDir, { recursive: true });
|
|
7948
8089
|
const patch = await git2(run, baseline.root, ["diff", "--binary", "HEAD"], { raw: true });
|
|
7949
|
-
await fsp9.writeFile(
|
|
8090
|
+
await fsp9.writeFile(path16.join(quarantineDir, "tracked.patch"), patch, "utf8");
|
|
7950
8091
|
for (const relative of paths.untracked) {
|
|
7951
|
-
const source =
|
|
7952
|
-
const target =
|
|
7953
|
-
await fsp9.mkdir(
|
|
8092
|
+
const source = path16.join(baseline.root, relative);
|
|
8093
|
+
const target = path16.join(quarantineDir, "untracked", relative);
|
|
8094
|
+
await fsp9.mkdir(path16.dirname(target), { recursive: true });
|
|
7954
8095
|
await fsp9.copyFile(source, target);
|
|
7955
8096
|
}
|
|
7956
|
-
await fsp9.writeFile(
|
|
8097
|
+
await fsp9.writeFile(path16.join(quarantineDir, "manifest.json"), `${JSON.stringify({
|
|
7957
8098
|
taskId,
|
|
7958
8099
|
canonicalRoot: baseline.root,
|
|
7959
8100
|
canonicalHead: baseline.head,
|
|
@@ -7975,8 +8116,8 @@ async function restoreExactCanonicalPaths(baseline, evidence, run) {
|
|
|
7975
8116
|
]);
|
|
7976
8117
|
}
|
|
7977
8118
|
for (const relative of evidence.untracked) {
|
|
7978
|
-
const target =
|
|
7979
|
-
const prefix = `${
|
|
8119
|
+
const target = path16.resolve(baseline.root, relative);
|
|
8120
|
+
const prefix = `${path16.resolve(baseline.root)}${path16.sep}`;
|
|
7980
8121
|
if (!target.startsWith(prefix) || !fs8.existsSync(target)) continue;
|
|
7981
8122
|
await fsp9.rm(target, { force: true });
|
|
7982
8123
|
}
|
|
@@ -8013,7 +8154,7 @@ var init_isolation_audit = __esm({
|
|
|
8013
8154
|
init_process_runner2();
|
|
8014
8155
|
splitZ2 = (value) => String(value || "").split("\0").map((item) => item.trim()).filter(Boolean);
|
|
8015
8156
|
samePath2 = (left, right) => {
|
|
8016
|
-
const [a, b] = [left, right].map((value) =>
|
|
8157
|
+
const [a, b] = [left, right].map((value) => path16.resolve(value));
|
|
8017
8158
|
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
8018
8159
|
};
|
|
8019
8160
|
}
|
|
@@ -8022,7 +8163,7 @@ var init_isolation_audit = __esm({
|
|
|
8022
8163
|
// ../../scripts/virtual-office/code-runner/recovery-ledger.mjs
|
|
8023
8164
|
import fs9 from "node:fs";
|
|
8024
8165
|
import fsp10 from "node:fs/promises";
|
|
8025
|
-
import
|
|
8166
|
+
import path17 from "node:path";
|
|
8026
8167
|
function recoveryTaskId(prompt) {
|
|
8027
8168
|
const match = String(prompt || "").match(/VO_RECOVERY_FROM_CODE_TASK:\s*([0-9a-f-]{36})/i);
|
|
8028
8169
|
return match ? match[1].toLowerCase() : null;
|
|
@@ -8036,10 +8177,10 @@ function cloneLeaf(repo) {
|
|
|
8036
8177
|
function recoveryLedgerCandidates(repo, clonesRoot2) {
|
|
8037
8178
|
const leaf = cloneLeaf(repo);
|
|
8038
8179
|
if (!leaf || !clonesRoot2) return [];
|
|
8039
|
-
const canonical =
|
|
8180
|
+
const canonical = path17.join(clonesRoot2, leaf);
|
|
8040
8181
|
return [
|
|
8041
|
-
|
|
8042
|
-
|
|
8182
|
+
path17.join(clonesRoot2, ".agent-worktrees", leaf, "recovery-ledger.jsonl"),
|
|
8183
|
+
path17.join(canonical, ".agent-worktrees", "recovery-ledger.jsonl")
|
|
8043
8184
|
];
|
|
8044
8185
|
}
|
|
8045
8186
|
async function readLedger(file, readFile4) {
|
|
@@ -8217,7 +8358,7 @@ var code_runner_daemon_exports = {};
|
|
|
8217
8358
|
__export(code_runner_daemon_exports, {
|
|
8218
8359
|
main: () => main
|
|
8219
8360
|
});
|
|
8220
|
-
import
|
|
8361
|
+
import os4 from "node:os";
|
|
8221
8362
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
8222
8363
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
8223
8364
|
function log2(msg) {
|
|
@@ -8227,7 +8368,7 @@ function loadConfig(env2 = process.env) {
|
|
|
8227
8368
|
const servedOperators = parseList(env2.VO_CODE_RUNNER_OPERATOR_IDS);
|
|
8228
8369
|
const allowAmbientGithub = env2.VO_CODE_RUNNER_ALLOW_AMBIENT_GH === "1";
|
|
8229
8370
|
return {
|
|
8230
|
-
runnerId: env2.VO_CODE_RUNNER_ID || `vo-code-runner-${
|
|
8371
|
+
runnerId: env2.VO_CODE_RUNNER_ID || `vo-code-runner-${os4.hostname()}`,
|
|
8231
8372
|
// BYO multi-agent: {agent, runner, runnerBin} — VO_CODE_RUNNER_AGENT selects the provider.
|
|
8232
8373
|
...resolveRunner(env2, { warn: (m) => log2(`agent-select: ${m}`) }),
|
|
8233
8374
|
permissionMode: env2.VO_CODE_RUNNER_PERMISSION_MODE || "acceptEdits",
|
|
@@ -8240,7 +8381,7 @@ function loadConfig(env2 = process.env) {
|
|
|
8240
8381
|
// 'Sees ALL agents': how often to forward the local session spool to the
|
|
8241
8382
|
// cloud (best-effort). Default 30s. Set 0 to disable forwarding.
|
|
8242
8383
|
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-${
|
|
8384
|
+
operatorSeed: env2.VO_LOCAL_OPERATOR_SEED || env2.VO_CODE_RUNNER_ID || `local-${os4.hostname()}`,
|
|
8244
8385
|
cancelPollMs: Math.max(1e3, Number(env2.VO_CODE_RUNNER_CANCEL_POLL_MS || 2500) || 2500),
|
|
8245
8386
|
// Hard cap OFF by default (0=no timer; work preserved via #7218 draft-PR). Set ms>0 to enforce; invalid→0.
|
|
8246
8387
|
maxWallClockMs: ((n) => Number.isFinite(n) && n >= 0 ? n : 0)(Number(env2.VO_CODE_RUNNER_MAX_WALL_CLOCK_MS ?? NaN)),
|
|
@@ -8438,6 +8579,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
8438
8579
|
await sweepStaleTaskAttachmentDirectories().catch((error) => log2(`stale attachment cleanup failed: ${error.message}`));
|
|
8439
8580
|
const client = createControlPlaneClient({ env: env2 });
|
|
8440
8581
|
const runnerInstanceId = randomUUID2();
|
|
8582
|
+
bootstrapOrphanReaper({ instanceId: runnerInstanceId, log: log2 });
|
|
8441
8583
|
let reconcileStale = true;
|
|
8442
8584
|
let stopping = false;
|
|
8443
8585
|
let active = 0;
|
|
@@ -8550,6 +8692,7 @@ var init_code_runner_daemon = __esm({
|
|
|
8550
8692
|
init_resolve_runner();
|
|
8551
8693
|
init_rate_limit_resume();
|
|
8552
8694
|
init_publish();
|
|
8695
|
+
init_orphan_agent_reaper();
|
|
8553
8696
|
init_publish_async();
|
|
8554
8697
|
init_resume_branch();
|
|
8555
8698
|
init_task_prompt();
|