@algosuite/vo-mcp 0.2.0-beta.30 → 0.2.0-beta.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-auth-probe-cli.mjs +187 -6
- package/dist/cli.js +65 -6
- package/dist/cli.js.map +2 -2
- package/dist/index.js +65 -6
- package/dist/index.js.map +2 -2
- package/dist/runner-cli.js +935 -166
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +99 -2
- package/dist/runner-supervisor.js.map +4 -4
- package/package.json +2 -2
package/dist/runner-cli.js
CHANGED
|
@@ -2582,6 +2582,11 @@ var init_control_plane_auth_stub = __esm({
|
|
|
2582
2582
|
});
|
|
2583
2583
|
|
|
2584
2584
|
// ../../scripts/virtual-office/code-runner/control-plane-client.mjs
|
|
2585
|
+
var control_plane_client_exports = {};
|
|
2586
|
+
__export(control_plane_client_exports, {
|
|
2587
|
+
ClaimAuthorityChangedError: () => ClaimAuthorityChangedError,
|
|
2588
|
+
createControlPlaneClient: () => createControlPlaneClient
|
|
2589
|
+
});
|
|
2585
2590
|
async function resolveBearer(env2) {
|
|
2586
2591
|
const adminToken = env2.VO_CONTROL_PLANE_ADMIN_TOKEN;
|
|
2587
2592
|
if (adminToken) return adminToken;
|
|
@@ -2614,11 +2619,11 @@ function createControlPlaneClient({
|
|
|
2614
2619
|
const resolvedBaseUrl = baseUrl ?? env2.VO_CONTROL_PLANE_URL ?? "";
|
|
2615
2620
|
if (!resolvedBaseUrl) throw new Error("VO_CONTROL_PLANE_URL is required for the code-runner daemon");
|
|
2616
2621
|
const root = resolvedBaseUrl.replace(/\/+$/, "");
|
|
2617
|
-
async function req(method,
|
|
2622
|
+
async function req(method, path23, body, { timeoutMs } = {}) {
|
|
2618
2623
|
const bearer = await resolveBearer(env2);
|
|
2619
2624
|
const controller = timeoutMs ? new AbortController() : null;
|
|
2620
2625
|
let timeoutId;
|
|
2621
|
-
const request = Promise.resolve(fetchImpl(`${root}${
|
|
2626
|
+
const request = Promise.resolve(fetchImpl(`${root}${path23}`, {
|
|
2622
2627
|
method,
|
|
2623
2628
|
headers: {
|
|
2624
2629
|
"content-type": "application/json",
|
|
@@ -2631,7 +2636,7 @@ function createControlPlaneClient({
|
|
|
2631
2636
|
const timeout = new Promise((_, reject) => {
|
|
2632
2637
|
timeoutId = setTimeout(() => {
|
|
2633
2638
|
controller.abort();
|
|
2634
|
-
reject(new Error(`control-plane ${
|
|
2639
|
+
reject(new Error(`control-plane ${path23} timed out after ${timeoutMs}ms`));
|
|
2635
2640
|
}, timeoutMs);
|
|
2636
2641
|
});
|
|
2637
2642
|
try {
|
|
@@ -2640,7 +2645,7 @@ function createControlPlaneClient({
|
|
|
2640
2645
|
clearTimeout(timeoutId);
|
|
2641
2646
|
}
|
|
2642
2647
|
}
|
|
2643
|
-
const taskReq = (method,
|
|
2648
|
+
const taskReq = (method, path23, body, options = {}) => req(method, path23, body, { timeoutMs: taskRequestTimeoutMs, ...options });
|
|
2644
2649
|
return {
|
|
2645
2650
|
...makeAutonomousDispatchAdmissionClient(
|
|
2646
2651
|
req,
|
|
@@ -2763,8 +2768,8 @@ function createControlPlaneClient({
|
|
|
2763
2768
|
return listAllPrOpenedTasks(taskReq);
|
|
2764
2769
|
},
|
|
2765
2770
|
async downloadTaskAttachment(taskId, attachmentId) {
|
|
2766
|
-
const
|
|
2767
|
-
const res = await taskReq("GET",
|
|
2771
|
+
const path23 = `/api/v1/code-task/${encodeURIComponent(taskId)}/attachment/${encodeURIComponent(attachmentId)}`;
|
|
2772
|
+
const res = await taskReq("GET", path23);
|
|
2768
2773
|
if (res.status === 401) cachedFirebaseToken = null;
|
|
2769
2774
|
if (!res.ok) throw new Error(`attachment download failed: HTTP ${res.status}`);
|
|
2770
2775
|
return Buffer.from(await res.arrayBuffer());
|
|
@@ -4870,6 +4875,188 @@ var init_cursor_runner = __esm({
|
|
|
4870
4875
|
}
|
|
4871
4876
|
});
|
|
4872
4877
|
|
|
4878
|
+
// ../../scripts/virtual-office/code-runner/ollama-agent-tools.mjs
|
|
4879
|
+
var MAX_READ_BYTES, MAX_WRITE_BYTES, TOOL_DEFS, TOOL_NAMES, READ_ONLY_TOOL_NAMES, READ_ONLY_TOOL_DEFS;
|
|
4880
|
+
var init_ollama_agent_tools = __esm({
|
|
4881
|
+
"../../scripts/virtual-office/code-runner/ollama-agent-tools.mjs"() {
|
|
4882
|
+
"use strict";
|
|
4883
|
+
MAX_READ_BYTES = 64 * 1024;
|
|
4884
|
+
MAX_WRITE_BYTES = 512 * 1024;
|
|
4885
|
+
TOOL_DEFS = [
|
|
4886
|
+
{
|
|
4887
|
+
type: "function",
|
|
4888
|
+
function: {
|
|
4889
|
+
name: "read_file",
|
|
4890
|
+
description: "Read a UTF-8 text file inside the working directory. Returns up to 64 KiB.",
|
|
4891
|
+
parameters: {
|
|
4892
|
+
type: "object",
|
|
4893
|
+
properties: {
|
|
4894
|
+
path: { type: "string", description: "File path relative to the working directory." }
|
|
4895
|
+
},
|
|
4896
|
+
required: ["path"]
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
},
|
|
4900
|
+
{
|
|
4901
|
+
type: "function",
|
|
4902
|
+
function: {
|
|
4903
|
+
name: "list_files",
|
|
4904
|
+
description: "List entries in a directory inside the working directory (files and subdirs).",
|
|
4905
|
+
parameters: {
|
|
4906
|
+
type: "object",
|
|
4907
|
+
properties: {
|
|
4908
|
+
path: { type: "string", description: 'Directory path relative to the working directory. Default ".".' }
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
},
|
|
4913
|
+
{
|
|
4914
|
+
type: "function",
|
|
4915
|
+
function: {
|
|
4916
|
+
name: "write_file",
|
|
4917
|
+
description: "Create or overwrite a UTF-8 text file inside the working directory. Parent dirs are created.",
|
|
4918
|
+
parameters: {
|
|
4919
|
+
type: "object",
|
|
4920
|
+
properties: {
|
|
4921
|
+
path: { type: "string", description: "File path relative to the working directory." },
|
|
4922
|
+
content: { type: "string", description: "Full new file contents." }
|
|
4923
|
+
},
|
|
4924
|
+
required: ["path", "content"]
|
|
4925
|
+
}
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
];
|
|
4929
|
+
TOOL_NAMES = TOOL_DEFS.map((t) => t.function.name);
|
|
4930
|
+
READ_ONLY_TOOL_NAMES = Object.freeze(["read_file", "list_files"]);
|
|
4931
|
+
READ_ONLY_TOOL_DEFS = Object.freeze(
|
|
4932
|
+
TOOL_DEFS.filter((tool) => READ_ONLY_TOOL_NAMES.includes(tool.function.name))
|
|
4933
|
+
);
|
|
4934
|
+
}
|
|
4935
|
+
});
|
|
4936
|
+
|
|
4937
|
+
// ../../scripts/virtual-office/code-runner/ollama-agent-core.mjs
|
|
4938
|
+
function parseOllamaAgentEvent(line) {
|
|
4939
|
+
const trimmed = String(line || "").trim();
|
|
4940
|
+
if (!trimmed) return null;
|
|
4941
|
+
let evt;
|
|
4942
|
+
try {
|
|
4943
|
+
evt = JSON.parse(trimmed);
|
|
4944
|
+
} catch {
|
|
4945
|
+
return null;
|
|
4946
|
+
}
|
|
4947
|
+
if (!evt || typeof evt !== "object") return null;
|
|
4948
|
+
if (evt.type === "progress") {
|
|
4949
|
+
const text = String(evt.text || "").trim();
|
|
4950
|
+
return text ? { kind: "progress", text } : null;
|
|
4951
|
+
}
|
|
4952
|
+
if (evt.type === "tool") {
|
|
4953
|
+
const via = evt.recovered ? " (recovered from text)" : "";
|
|
4954
|
+
const label = `${evt.ok === false ? "tool failed" : "tool"}: ${evt.name}${evt.path ? ` ${evt.path}` : ""}${via}`;
|
|
4955
|
+
return { kind: "progress", text: label };
|
|
4956
|
+
}
|
|
4957
|
+
if (evt.type === "result") {
|
|
4958
|
+
const usage = evt.usage || null;
|
|
4959
|
+
const tokenUsage = usage ? { inputTokens: usage.inputTokens ?? null, outputTokens: usage.outputTokens ?? null, totalTokens: usage.totalTokens ?? null } : void 0;
|
|
4960
|
+
return {
|
|
4961
|
+
kind: "result",
|
|
4962
|
+
isError: Boolean(evt.isError),
|
|
4963
|
+
costUsd: 0,
|
|
4964
|
+
// sovereign local inference is free — no meter.
|
|
4965
|
+
summary: String(evt.summary || (evt.isError ? "local run failed" : "completed")),
|
|
4966
|
+
numTurns: Number.isInteger(evt.numTurns) ? evt.numTurns : null,
|
|
4967
|
+
...tokenUsage ? { tokenUsage } : {},
|
|
4968
|
+
// Pass the sovereign receipt through to the daemon. Omitted entirely when
|
|
4969
|
+
// absent so the event shape is unchanged for every other transport.
|
|
4970
|
+
...evt.receipt ? { receipt: evt.receipt } : {}
|
|
4971
|
+
};
|
|
4972
|
+
}
|
|
4973
|
+
return null;
|
|
4974
|
+
}
|
|
4975
|
+
var MAX_TURNS_DEFAULT, NUM_CTX_DEFAULT;
|
|
4976
|
+
var init_ollama_agent_core = __esm({
|
|
4977
|
+
"../../scripts/virtual-office/code-runner/ollama-agent-core.mjs"() {
|
|
4978
|
+
"use strict";
|
|
4979
|
+
init_ollama_agent_tools();
|
|
4980
|
+
init_ollama_agent_tools();
|
|
4981
|
+
MAX_TURNS_DEFAULT = 20;
|
|
4982
|
+
NUM_CTX_DEFAULT = 16384;
|
|
4983
|
+
}
|
|
4984
|
+
});
|
|
4985
|
+
|
|
4986
|
+
// ../../scripts/virtual-office/code-runner/ollama-native-transport.mjs
|
|
4987
|
+
import { fileURLToPath } from "node:url";
|
|
4988
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
4989
|
+
function resolveLocalNativeProfile(env2 = process.env) {
|
|
4990
|
+
const profile = String(env2.VO_CODE_RUNNER_LOCAL_PROFILE || "").trim().toLowerCase() || DEFAULT_LOCAL_NATIVE_PROFILE;
|
|
4991
|
+
if (!LOCAL_NATIVE_PROFILES.includes(profile)) {
|
|
4992
|
+
throw new Error(`local-model runner (native): unknown profile "${profile}" (coding|verification).`);
|
|
4993
|
+
}
|
|
4994
|
+
return profile;
|
|
4995
|
+
}
|
|
4996
|
+
function resolveLocalTransport(env2 = process.env) {
|
|
4997
|
+
return String(env2.VO_CODE_RUNNER_LOCAL_TRANSPORT || "").trim().toLowerCase() === "native" ? "native" : DEFAULT_LOCAL_TRANSPORT;
|
|
4998
|
+
}
|
|
4999
|
+
function ollamaAgentScriptPath() {
|
|
5000
|
+
return join2(dirname2(fileURLToPath(import.meta.url)), "ollama-agent.mjs");
|
|
5001
|
+
}
|
|
5002
|
+
function posIntOr(raw, fallback) {
|
|
5003
|
+
const n = Number(String(raw ?? "").trim());
|
|
5004
|
+
return Number.isInteger(n) && n > 0 ? n : fallback;
|
|
5005
|
+
}
|
|
5006
|
+
function buildOllamaAgentArgs({ model, numCtx, maxTurns, profile = DEFAULT_LOCAL_NATIVE_PROFILE } = {}) {
|
|
5007
|
+
return [
|
|
5008
|
+
ollamaAgentScriptPath(),
|
|
5009
|
+
"--model",
|
|
5010
|
+
String(model),
|
|
5011
|
+
"--profile",
|
|
5012
|
+
String(profile),
|
|
5013
|
+
"--num-ctx",
|
|
5014
|
+
String(posIntOr(numCtx, NUM_CTX_DEFAULT)),
|
|
5015
|
+
"--max-turns",
|
|
5016
|
+
String(posIntOr(maxTurns, MAX_TURNS_DEFAULT))
|
|
5017
|
+
];
|
|
5018
|
+
}
|
|
5019
|
+
function buildLocalNativeArgs(opts = {}, env2 = process.env) {
|
|
5020
|
+
const provider = resolveLocalProvider(env2);
|
|
5021
|
+
if (provider !== "ollama") {
|
|
5022
|
+
throw new Error(
|
|
5023
|
+
`local-model runner (native): the native tool-loop executor speaks Ollama's /api/chat; provider "${provider}" is not supported on native transport. Set VO_CODE_RUNNER_LOCAL_PROVIDER=ollama, or use VO_CODE_RUNNER_LOCAL_TRANSPORT=codex for LM Studio.`
|
|
5024
|
+
);
|
|
5025
|
+
}
|
|
5026
|
+
const model = resolveLocalModel(env2);
|
|
5027
|
+
if (!model) {
|
|
5028
|
+
throw new Error(
|
|
5029
|
+
"local-model runner (native): set VO_CODE_RUNNER_LOCAL_MODEL to a coding model your Ollama server already has (e.g. qwen2.5-coder:7b). Refusing to run with no explicit model (fail-closed)."
|
|
5030
|
+
);
|
|
5031
|
+
}
|
|
5032
|
+
if (!isValidLocalModel(model)) {
|
|
5033
|
+
throw new Error(`local-model runner (native): "${model}" is not a valid local model id.`);
|
|
5034
|
+
}
|
|
5035
|
+
const baseUrl = resolveLocalBaseUrl(env2);
|
|
5036
|
+
if (baseUrl && !isLoopbackBaseUrl(baseUrl)) {
|
|
5037
|
+
throw new Error(
|
|
5038
|
+
"local-model runner (native): VO_CODE_RUNNER_LOCAL_BASE_URL must be a loopback http(s) URL (localhost / 127.0.0.1 / [::1]). Remote endpoints are refused \u2014 use the Model Firewall lanes."
|
|
5039
|
+
);
|
|
5040
|
+
}
|
|
5041
|
+
return buildOllamaAgentArgs({
|
|
5042
|
+
model,
|
|
5043
|
+
profile: resolveLocalNativeProfile(env2),
|
|
5044
|
+
numCtx: env2.VO_CODE_RUNNER_LOCAL_NUM_CTX,
|
|
5045
|
+
maxTurns: env2.VO_CODE_RUNNER_LOCAL_MAX_TURNS
|
|
5046
|
+
});
|
|
5047
|
+
}
|
|
5048
|
+
var DEFAULT_LOCAL_TRANSPORT, LOCAL_NATIVE_PROFILES, DEFAULT_LOCAL_NATIVE_PROFILE;
|
|
5049
|
+
var init_ollama_native_transport = __esm({
|
|
5050
|
+
"../../scripts/virtual-office/code-runner/ollama-native-transport.mjs"() {
|
|
5051
|
+
"use strict";
|
|
5052
|
+
init_ollama_agent_core();
|
|
5053
|
+
init_local_model_runner();
|
|
5054
|
+
DEFAULT_LOCAL_TRANSPORT = "codex";
|
|
5055
|
+
LOCAL_NATIVE_PROFILES = Object.freeze(["coding", "verification"]);
|
|
5056
|
+
DEFAULT_LOCAL_NATIVE_PROFILE = "coding";
|
|
5057
|
+
}
|
|
5058
|
+
});
|
|
5059
|
+
|
|
4873
5060
|
// ../../scripts/virtual-office/code-runner/local-model-runner.mjs
|
|
4874
5061
|
function resolveLocalProvider(env2 = process.env) {
|
|
4875
5062
|
return String(env2.VO_CODE_RUNNER_LOCAL_PROVIDER || "").trim().toLowerCase() || DEFAULT_LOCAL_PROVIDER;
|
|
@@ -4943,20 +5130,37 @@ function buildLocalArgs(opts = {}, env2 = process.env) {
|
|
|
4943
5130
|
}
|
|
4944
5131
|
function applyLocalAuthEnv(baseEnv = process.env, configEnv = process.env) {
|
|
4945
5132
|
const out = withAgentKey("local", baseEnv);
|
|
5133
|
+
for (const key of Object.keys(out)) {
|
|
5134
|
+
if (FORBIDDEN_LOCAL_CHILD_CREDENTIALS.has(key.toUpperCase())) delete out[key];
|
|
5135
|
+
}
|
|
4946
5136
|
const baseUrl = resolveLocalBaseUrl(configEnv);
|
|
4947
5137
|
if (baseUrl && isLoopbackBaseUrl(baseUrl) && resolveLocalProvider(configEnv) === "ollama" && !String(out.OLLAMA_HOST || "").trim()) {
|
|
4948
5138
|
out.OLLAMA_HOST = baseUrl.replace(/\/+$/, "");
|
|
4949
5139
|
}
|
|
4950
5140
|
return out;
|
|
4951
5141
|
}
|
|
4952
|
-
var LOCAL_API_KEY_ENV, LOCAL_PROVIDERS, DEFAULT_LOCAL_PROVIDER, LOCAL_PROBE_URLS, remoteDesiredLocalModel, LOCAL_MODEL_RE, LocalModelRunner, localModelRunner;
|
|
5142
|
+
var LOCAL_API_KEY_ENV, FORBIDDEN_LOCAL_CHILD_CREDENTIALS, LOCAL_PROVIDERS, DEFAULT_LOCAL_PROVIDER, LOCAL_PROBE_URLS, remoteDesiredLocalModel, LOCAL_MODEL_RE, LocalModelRunner, localModelRunner;
|
|
4953
5143
|
var init_local_model_runner = __esm({
|
|
4954
5144
|
"../../scripts/virtual-office/code-runner/local-model-runner.mjs"() {
|
|
4955
5145
|
"use strict";
|
|
4956
5146
|
init_codex_runner();
|
|
4957
5147
|
init_agent_key_store();
|
|
4958
5148
|
init_agent_auth_tier();
|
|
5149
|
+
init_ollama_agent_core();
|
|
5150
|
+
init_ollama_native_transport();
|
|
4959
5151
|
LOCAL_API_KEY_ENV = "VO_CODE_RUNNER_LOCAL_API_KEY";
|
|
5152
|
+
FORBIDDEN_LOCAL_CHILD_CREDENTIALS = /* @__PURE__ */ new Set([
|
|
5153
|
+
"ANTHROPIC_API_KEY",
|
|
5154
|
+
"AWS_ACCESS_KEY_ID",
|
|
5155
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
5156
|
+
"AWS_SESSION_TOKEN",
|
|
5157
|
+
"FIREBASE_TOKEN",
|
|
5158
|
+
"GH_TOKEN",
|
|
5159
|
+
"GITHUB_TOKEN",
|
|
5160
|
+
"GOOGLE_API_KEY",
|
|
5161
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
5162
|
+
"OPENAI_API_KEY"
|
|
5163
|
+
]);
|
|
4960
5164
|
LOCAL_PROVIDERS = ["ollama", "lmstudio"];
|
|
4961
5165
|
DEFAULT_LOCAL_PROVIDER = "ollama";
|
|
4962
5166
|
LOCAL_PROBE_URLS = {
|
|
@@ -4977,19 +5181,25 @@ var init_local_model_runner = __esm({
|
|
|
4977
5181
|
this.env = env2;
|
|
4978
5182
|
this.fetchImpl = fetchImpl;
|
|
4979
5183
|
}
|
|
4980
|
-
/**
|
|
5184
|
+
/**
|
|
5185
|
+
* Transport binary. codex transport → the codex CLI. native transport →
|
|
5186
|
+
* this daemon's own node (process.execPath), which runs ollama-agent.mjs; no
|
|
5187
|
+
* external CLI is involved on the native path.
|
|
5188
|
+
*/
|
|
4981
5189
|
get binary() {
|
|
4982
|
-
return this.resolveBinary();
|
|
5190
|
+
return resolveLocalTransport(this.env) === "native" ? process.execPath : this.resolveBinary();
|
|
4983
5191
|
}
|
|
4984
5192
|
buildArgs(opts = {}) {
|
|
4985
|
-
return buildLocalArgs(opts, this.env);
|
|
5193
|
+
return resolveLocalTransport(this.env) === "native" ? buildLocalNativeArgs(opts, this.env) : buildLocalArgs(opts, this.env);
|
|
4986
5194
|
}
|
|
4987
5195
|
/**
|
|
4988
|
-
*
|
|
4989
|
-
*
|
|
4990
|
-
*
|
|
5196
|
+
* native transport → parse the executor's own JSONL contract. codex transport
|
|
5197
|
+
* → codex JSONL maps identically, except a sovereign local model has no vendor
|
|
5198
|
+
* bill: codex omits total_cost_usd for OSS runs, so turn that known fact into a
|
|
5199
|
+
* measured zero at the producer. (The native parser already stamps costUsd:0.)
|
|
4991
5200
|
*/
|
|
4992
5201
|
parseEvent(line) {
|
|
5202
|
+
if (resolveLocalTransport(this.env) === "native") return parseOllamaAgentEvent(line);
|
|
4993
5203
|
const event = parseCodexEvent(line);
|
|
4994
5204
|
return event?.kind === "result" ? { ...event, costUsd: 0 } : event;
|
|
4995
5205
|
}
|
|
@@ -5488,9 +5698,9 @@ var init_rate_limit_resume_state = __esm({
|
|
|
5488
5698
|
|
|
5489
5699
|
// ../../scripts/virtual-office/code-runner/rate-limit-resume.mjs
|
|
5490
5700
|
import { homedir as homedir3 } from "node:os";
|
|
5491
|
-
import { join as
|
|
5701
|
+
import { join as join3 } from "node:path";
|
|
5492
5702
|
function resumeQueuePath() {
|
|
5493
|
-
return
|
|
5703
|
+
return join3(homedir3(), ".claude", "resume-queue.jsonl");
|
|
5494
5704
|
}
|
|
5495
5705
|
function buildResumeEntry({ task = {}, resumeAfter = null, summary = "", at } = {}) {
|
|
5496
5706
|
return {
|
|
@@ -5692,7 +5902,7 @@ var init_auto_merge = __esm({
|
|
|
5692
5902
|
// ../../scripts/virtual-office/code-runner/pr-overlap-gate.mjs
|
|
5693
5903
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
5694
5904
|
import { existsSync as existsSync6 } from "node:fs";
|
|
5695
|
-
import { fileURLToPath } from "node:url";
|
|
5905
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5696
5906
|
function stripCredentials(env2 = process.env) {
|
|
5697
5907
|
const safe = { ...env2 };
|
|
5698
5908
|
for (const key of CREDENTIAL_ENV_KEYS) delete safe[key];
|
|
@@ -5718,7 +5928,7 @@ var init_pr_overlap_gate = __esm({
|
|
|
5718
5928
|
TRUSTED_OVERLAP_CANDIDATES = [
|
|
5719
5929
|
new URL("../../ci/check-local-pr-overlap.mjs", import.meta.url),
|
|
5720
5930
|
new URL("./ci/check-local-pr-overlap.js", import.meta.url)
|
|
5721
|
-
].map((candidate) =>
|
|
5931
|
+
].map((candidate) => fileURLToPath2(candidate));
|
|
5722
5932
|
CREDENTIAL_ENV_KEYS = Object.freeze([
|
|
5723
5933
|
"GH_TOKEN",
|
|
5724
5934
|
"GITHUB_TOKEN",
|
|
@@ -5771,14 +5981,14 @@ function parsePorcelainZ(out) {
|
|
|
5771
5981
|
for (let i = 0; i < tokens.length; i += 1) {
|
|
5772
5982
|
const token2 = tokens[i];
|
|
5773
5983
|
if (!token2) continue;
|
|
5774
|
-
const
|
|
5775
|
-
if (
|
|
5984
|
+
const path23 = token2.slice(3);
|
|
5985
|
+
if (path23) files.push(path23);
|
|
5776
5986
|
if (token2[0] === "R" || token2[0] === "C") i += 1;
|
|
5777
5987
|
}
|
|
5778
5988
|
return files;
|
|
5779
5989
|
}
|
|
5780
|
-
function isAgentScratch(
|
|
5781
|
-
const normalized = String(
|
|
5990
|
+
function isAgentScratch(path23) {
|
|
5991
|
+
const normalized = String(path23 || "");
|
|
5782
5992
|
return SCRATCH_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
5783
5993
|
}
|
|
5784
5994
|
var SCRATCH_PATTERNS;
|
|
@@ -5845,6 +6055,540 @@ var init_publish = __esm({
|
|
|
5845
6055
|
}
|
|
5846
6056
|
});
|
|
5847
6057
|
|
|
6058
|
+
// ../../scripts/virtual-office/test-gen/auto-tier.mjs
|
|
6059
|
+
function lower(s) {
|
|
6060
|
+
return typeof s === "string" ? s.toLowerCase() : "";
|
|
6061
|
+
}
|
|
6062
|
+
function isAlgoProduct(product) {
|
|
6063
|
+
return /^algo/i.test(String(product || ""));
|
|
6064
|
+
}
|
|
6065
|
+
function isAdminRoute(route) {
|
|
6066
|
+
return /(^|\/)admin(\/|$)/i.test(String(route || ""));
|
|
6067
|
+
}
|
|
6068
|
+
function importsMatch(imports, re) {
|
|
6069
|
+
return Array.isArray(imports) && imports.some((i) => re.test(String(i || "")));
|
|
6070
|
+
}
|
|
6071
|
+
function classifyTier(contract = {}) {
|
|
6072
|
+
const product = lower(contract.product);
|
|
6073
|
+
const callable = String(contract.callable || "");
|
|
6074
|
+
const route = String(contract.route || "");
|
|
6075
|
+
const imports = contract.imports;
|
|
6076
|
+
const ov = contract.tier_override;
|
|
6077
|
+
if (ov === 1 || ov === 2 || ov === 3 || ov === 4) {
|
|
6078
|
+
return { tier: ov, rationale: `operator override \u2192 Tier ${ov}`, tier_override: true };
|
|
6079
|
+
}
|
|
6080
|
+
const algo = isAlgoProduct(product);
|
|
6081
|
+
let tier;
|
|
6082
|
+
let why;
|
|
6083
|
+
const legalDomain = LEGAL_PRODUCTS.has(product);
|
|
6084
|
+
const hasGovernedSource = Boolean(contract.authoritative_source_url) || importsMatch(imports, LEGAL_IMPORT_RE);
|
|
6085
|
+
if (legalDomain && hasGovernedSource) {
|
|
6086
|
+
tier = 4;
|
|
6087
|
+
why = `legal-correctness domain (${product}) with a governed source \u2192 source-grounded Tier 4`;
|
|
6088
|
+
} else if (isAdminRoute(route) || MONEY_OR_SAFETY_RE.test(callable)) {
|
|
6089
|
+
tier = 3;
|
|
6090
|
+
why = isAdminRoute(route) ? "admin/safety-critical route \u2192 real-time monitor Tier 3" : `money-moving or grading callable (${callable}) \u2192 real-time monitor Tier 3`;
|
|
6091
|
+
} else if (importsMatch(imports, GENERATIVE_RE) || GENERATIVE_CALLABLE_RE.test(callable)) {
|
|
6092
|
+
const long = Number(contract.workflow_seconds) > 30;
|
|
6093
|
+
tier = long ? 3 : 2;
|
|
6094
|
+
why = `generative/AI feature \u2192 E2E with verified results${long ? " + monitor (long workflow) Tier 3" : " Tier 2"}`;
|
|
6095
|
+
} else if (callable || route) {
|
|
6096
|
+
tier = 2;
|
|
6097
|
+
why = "standard business logic \u2192 E2E with verified results (read-back) Tier 2";
|
|
6098
|
+
} else {
|
|
6099
|
+
tier = 1;
|
|
6100
|
+
why = "pure navigation/surface, no backend effect \u2192 surface smoke Tier 1";
|
|
6101
|
+
}
|
|
6102
|
+
if (algo && tier < 2) {
|
|
6103
|
+
return {
|
|
6104
|
+
tier: 2,
|
|
6105
|
+
rationale: `${why}; raised to Tier 2 (E2E floor: Algo* apps never auto-pick surface-smoke-only)`,
|
|
6106
|
+
tier_override: false
|
|
6107
|
+
};
|
|
6108
|
+
}
|
|
6109
|
+
return { tier, rationale: why, tier_override: false };
|
|
6110
|
+
}
|
|
6111
|
+
function tierLabel(tier) {
|
|
6112
|
+
return {
|
|
6113
|
+
1: "Tier 1 \u2014 surface & navigation smoke",
|
|
6114
|
+
2: "Tier 2 \u2014 E2E with verified results",
|
|
6115
|
+
3: "Tier 3 \u2014 real-time monitor / sentinel",
|
|
6116
|
+
4: "Tier 4 \u2014 source-grounded governed-fact verification"
|
|
6117
|
+
}[tier] || `Tier ${tier}`;
|
|
6118
|
+
}
|
|
6119
|
+
var LEGAL_PRODUCTS, LEGAL_IMPORT_RE, GENERATIVE_RE, GENERATIVE_CALLABLE_RE, MONEY_OR_SAFETY_RE;
|
|
6120
|
+
var init_auto_tier = __esm({
|
|
6121
|
+
"../../scripts/virtual-office/test-gen/auto-tier.mjs"() {
|
|
6122
|
+
"use strict";
|
|
6123
|
+
LEGAL_PRODUCTS = /* @__PURE__ */ new Set(["algotax", "algolaw", "algoteach", "algolegal"]);
|
|
6124
|
+
LEGAL_IMPORT_RE = /functions-core-(tax|law)|cornell|irs|\bstatute\b/i;
|
|
6125
|
+
GENERATIVE_RE = /@google\/generative-ai|@anthropic|anthropic|openai|@google\/genai|consensus|\bllm\b/i;
|
|
6126
|
+
GENERATIVE_CALLABLE_RE = /generate|summari[sz]e|\bai\b|consensus|draft|classify/i;
|
|
6127
|
+
MONEY_OR_SAFETY_RE = /grade|payment|transfer|trade|charge|refund|payout|disburse|withdraw|remit/i;
|
|
6128
|
+
}
|
|
6129
|
+
});
|
|
6130
|
+
|
|
6131
|
+
// ../../scripts/virtual-office/test-gen/dispatch.mjs
|
|
6132
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
6133
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6134
|
+
import path14 from "node:path";
|
|
6135
|
+
function buildGenerationPrompt({ contract = {}, tier }) {
|
|
6136
|
+
const label = tierLabel(tier);
|
|
6137
|
+
const target = contract.callable ? `the \`${contract.callable}\` callable` : contract.route ? `the \`${contract.route}\` route` : contract.feature_name || "the feature";
|
|
6138
|
+
return [
|
|
6139
|
+
`Write a ${label} test for ${target} in product "${contract.product || "unknown"}".`,
|
|
6140
|
+
contract.source_file ? `Source: ${contract.source_file}.` : "",
|
|
6141
|
+
contract.expected_behavior ? `Expected behavior: ${contract.expected_behavior}.` : "",
|
|
6142
|
+
"",
|
|
6143
|
+
`TIER REQUIREMENT \u2014 ${TIER_GUIDANCE[tier] || TIER_GUIDANCE[2]}`,
|
|
6144
|
+
"",
|
|
6145
|
+
"Follow the AlgoSuite test-honesty standard: NO fake-green (no bare toBeTruthy, no broad",
|
|
6146
|
+
"try/catch that swallows failures, no treating INVALID_ARGUMENT / empty / null / SKIP as a",
|
|
6147
|
+
"pass). Use a real fixture (smoke@algosuite.ai) and real data shapes.",
|
|
6148
|
+
"",
|
|
6149
|
+
"After writing the test, it will be GATED server-side: deterministic ratchets, then",
|
|
6150
|
+
"multi-model consensus that it proves the behavior with VERIFIED-CORRECT expected values.",
|
|
6151
|
+
"A test that does not pass BOTH gates will NOT ship \u2014 so make the assertions real and the",
|
|
6152
|
+
"expected values known-correct. Leave the test file UNCOMMITTED; the runner opens the PR."
|
|
6153
|
+
].filter((l) => l !== "").join("\n");
|
|
6154
|
+
}
|
|
6155
|
+
function planTestGenDispatch({ contract = {} }) {
|
|
6156
|
+
const { tier, rationale } = classifyTier(contract);
|
|
6157
|
+
return {
|
|
6158
|
+
contract,
|
|
6159
|
+
tier,
|
|
6160
|
+
tier_label: tierLabel(tier),
|
|
6161
|
+
tier_rationale: rationale,
|
|
6162
|
+
generation_prompt: buildGenerationPrompt({ contract, tier })
|
|
6163
|
+
};
|
|
6164
|
+
}
|
|
6165
|
+
function buildTestGenTaskPrompt(dispatch = {}) {
|
|
6166
|
+
const contractJson = JSON.stringify(dispatch.contract ?? {});
|
|
6167
|
+
return `${TEST_GEN_MARKER} ${contractJson}
|
|
6168
|
+
|
|
6169
|
+
${dispatch.generation_prompt ?? ""}`;
|
|
6170
|
+
}
|
|
6171
|
+
function pickNextTarget({ gaps = [] }) {
|
|
6172
|
+
if (!Array.isArray(gaps) || gaps.length === 0) return null;
|
|
6173
|
+
const ranked = [...gaps].sort((a, b) => {
|
|
6174
|
+
const al = LEGAL.has(String(a.product)) ? 0 : 1;
|
|
6175
|
+
const bl = LEGAL.has(String(b.product)) ? 0 : 1;
|
|
6176
|
+
return al - bl;
|
|
6177
|
+
});
|
|
6178
|
+
return ranked[0];
|
|
6179
|
+
}
|
|
6180
|
+
function resolveRepo(argv, env2) {
|
|
6181
|
+
const repoArg = argv.indexOf("--repo");
|
|
6182
|
+
if (repoArg >= 0 && argv[repoArg + 1]) return argv[repoArg + 1];
|
|
6183
|
+
if (env2.VO_TEST_GEN_REPO) return env2.VO_TEST_GEN_REPO;
|
|
6184
|
+
const remote = spawnSync10("git", ["remote", "get-url", "origin"], { encoding: "utf8" });
|
|
6185
|
+
if (remote.status === 0) {
|
|
6186
|
+
const m = String(remote.stdout).trim().match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
6187
|
+
if (m) return m[1];
|
|
6188
|
+
}
|
|
6189
|
+
return null;
|
|
6190
|
+
}
|
|
6191
|
+
async function main(argv = process.argv.slice(2)) {
|
|
6192
|
+
const countArg = argv.indexOf("--count");
|
|
6193
|
+
const count3 = countArg >= 0 ? Math.max(1, Number(argv[countArg + 1]) || 1) : 1;
|
|
6194
|
+
const enqueue = argv.includes("--enqueue");
|
|
6195
|
+
const here = path14.dirname(fileURLToPath3(import.meta.url));
|
|
6196
|
+
const scan = spawnSync10("node", [path14.join(here, "coverage-scan.mjs"), "--limit", String(count3 * 8)], {
|
|
6197
|
+
encoding: "utf8",
|
|
6198
|
+
maxBuffer: 64 * 1024 * 1024
|
|
6199
|
+
});
|
|
6200
|
+
if (scan.status !== 0) {
|
|
6201
|
+
console.error(`[dispatch] coverage-scan failed: ${scan.stderr || scan.stdout}`);
|
|
6202
|
+
process.exit(1);
|
|
6203
|
+
}
|
|
6204
|
+
let gaps = [];
|
|
6205
|
+
try {
|
|
6206
|
+
gaps = JSON.parse(scan.stdout).gaps || [];
|
|
6207
|
+
} catch (err) {
|
|
6208
|
+
console.error(`[dispatch] could not parse scan output: ${err.message}`);
|
|
6209
|
+
process.exit(1);
|
|
6210
|
+
}
|
|
6211
|
+
const dispatches = [];
|
|
6212
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6213
|
+
let pool = gaps;
|
|
6214
|
+
while (dispatches.length < count3 && pool.length > 0) {
|
|
6215
|
+
const target = pickNextTarget({ gaps: pool });
|
|
6216
|
+
if (!target) break;
|
|
6217
|
+
const key = `${target.product}:${target.callable}`;
|
|
6218
|
+
if (!seen.has(key)) {
|
|
6219
|
+
seen.add(key);
|
|
6220
|
+
dispatches.push(planTestGenDispatch({ contract: target }));
|
|
6221
|
+
}
|
|
6222
|
+
pool = pool.filter((g) => `${g.product}:${g.callable}` !== key);
|
|
6223
|
+
}
|
|
6224
|
+
if (!enqueue) {
|
|
6225
|
+
console.log(JSON.stringify({ requested: count3, emitted: dispatches.length, dispatches }, null, 2));
|
|
6226
|
+
return;
|
|
6227
|
+
}
|
|
6228
|
+
const repo = resolveRepo(argv, process.env);
|
|
6229
|
+
if (!repo) {
|
|
6230
|
+
console.error("[dispatch] --enqueue needs a repo: pass --repo owner/name or set VO_TEST_GEN_REPO (could not derive from git origin)");
|
|
6231
|
+
process.exit(1);
|
|
6232
|
+
}
|
|
6233
|
+
const { createControlPlaneClient: createControlPlaneClient2 } = await Promise.resolve().then(() => (init_control_plane_client(), control_plane_client_exports));
|
|
6234
|
+
const client = createControlPlaneClient2({ env: process.env });
|
|
6235
|
+
const enqueued = [];
|
|
6236
|
+
for (const d of dispatches) {
|
|
6237
|
+
const task = await client.enqueueCodeTask({
|
|
6238
|
+
repo,
|
|
6239
|
+
prompt: buildTestGenTaskPrompt(d),
|
|
6240
|
+
max_turns: 40
|
|
6241
|
+
});
|
|
6242
|
+
const taskId = task && task.code_task_id ? task.code_task_id : "(unknown)";
|
|
6243
|
+
enqueued.push({ task_id: taskId, product: d.contract.product, callable: d.contract.callable, tier: d.tier_label });
|
|
6244
|
+
console.error(`[dispatch] enqueued ${d.tier_label} test-gen for ${d.contract.product}:${d.contract.callable} \u2192 task ${taskId}`);
|
|
6245
|
+
}
|
|
6246
|
+
console.log(JSON.stringify({ requested: count3, enqueued: enqueued.length, repo, tasks: enqueued }, null, 2));
|
|
6247
|
+
}
|
|
6248
|
+
var TEST_GEN_MARKER, TIER_GUIDANCE, LEGAL, invokedDirectly;
|
|
6249
|
+
var init_dispatch = __esm({
|
|
6250
|
+
"../../scripts/virtual-office/test-gen/dispatch.mjs"() {
|
|
6251
|
+
"use strict";
|
|
6252
|
+
init_auto_tier();
|
|
6253
|
+
TEST_GEN_MARKER = "[VO-TEST-GEN]";
|
|
6254
|
+
TIER_GUIDANCE = {
|
|
6255
|
+
1: "Surface/navigation smoke: assert the surface renders and the key controls are present. No backend effect needed.",
|
|
6256
|
+
2: "E2E with VERIFIED RESULTS: drive the real user/callable workflow, then READ BACK the produced artifact and assert KNOWN-CORRECT expected values (not just a 200 / truthiness).",
|
|
6257
|
+
3: "Real-time monitor / sentinel: drive the workflow AND verify the state transitions + safety rails (no money moved / graded / admin action without the guard). Assert the post-conditions, not just the response.",
|
|
6258
|
+
4: "Source-grounded governed-fact: assert expected values that are GROUNDED in the cited authoritative source (the contract's authoritative_source_url). The fixture and the expected number/string must trace to that source."
|
|
6259
|
+
};
|
|
6260
|
+
LEGAL = /* @__PURE__ */ new Set(["algotax", "algolaw", "algoteach", "algolegal"]);
|
|
6261
|
+
invokedDirectly = process.argv[1] && fileURLToPath3(import.meta.url) === path14.resolve(process.argv[1]);
|
|
6262
|
+
if (invokedDirectly) {
|
|
6263
|
+
main().catch((err) => {
|
|
6264
|
+
console.error(`[dispatch] ${err.message}`);
|
|
6265
|
+
process.exit(1);
|
|
6266
|
+
});
|
|
6267
|
+
}
|
|
6268
|
+
}
|
|
6269
|
+
});
|
|
6270
|
+
|
|
6271
|
+
// ../../scripts/virtual-office/test-gen/executor.mjs
|
|
6272
|
+
function consensusQuestion(tier) {
|
|
6273
|
+
const tierAsk = tier >= 4 ? " For this governed-fact (Tier 4) test, the expected values MUST be grounded in the cited authoritative source." : tier >= 3 ? " For this safety-critical (Tier 3) test, it must verify state transitions and the safety rails, not just a 200." : "";
|
|
6274
|
+
return "Does this test PROVE the stated behavior with VERIFIED-CORRECT expected values (not fake-green)? It must exercise the real product path (no stub/mock that bypasses the feature) and assert known-correct values, not placeholders." + tierAsk;
|
|
6275
|
+
}
|
|
6276
|
+
function buildContractSummary(contract, tier) {
|
|
6277
|
+
const parts = [
|
|
6278
|
+
`Feature: ${contract.feature_name || contract.callable || contract.route || "unnamed"}`,
|
|
6279
|
+
`Product: ${contract.product || "unknown"}`,
|
|
6280
|
+
contract.route ? `Route: ${contract.route}` : "",
|
|
6281
|
+
contract.callable ? `Callable: ${contract.callable}` : "",
|
|
6282
|
+
`Auto-selected tier: ${tierLabel(tier)}`,
|
|
6283
|
+
contract.expected_behavior ? `Expected behavior: ${contract.expected_behavior}` : "",
|
|
6284
|
+
contract.authoritative_source_url ? `Authoritative source: ${contract.authoritative_source_url}` : ""
|
|
6285
|
+
];
|
|
6286
|
+
return parts.filter(Boolean).join("\n");
|
|
6287
|
+
}
|
|
6288
|
+
async function gateGeneratedTest({ contract = {}, testSource = "", verify, taskId = "autotest" }) {
|
|
6289
|
+
if (typeof verify !== "function") throw new Error("gateGeneratedTest requires a `verify` transport");
|
|
6290
|
+
const { tier, rationale } = classifyTier(contract);
|
|
6291
|
+
const label = tierLabel(tier);
|
|
6292
|
+
const filename = typeof contract.test_filename === "string" ? contract.test_filename : void 0;
|
|
6293
|
+
const ratchets = await verify({
|
|
6294
|
+
task_id: taskId,
|
|
6295
|
+
gate_type: "ratchets",
|
|
6296
|
+
excerpt: testSource,
|
|
6297
|
+
...filename ? { context: { filename } } : {}
|
|
6298
|
+
});
|
|
6299
|
+
if (!ratchets || ratchets.approved !== true) {
|
|
6300
|
+
return {
|
|
6301
|
+
ship: false,
|
|
6302
|
+
tier,
|
|
6303
|
+
tierLabel: label,
|
|
6304
|
+
stage: "ratchets",
|
|
6305
|
+
reason: ratchets?.reason || "ratchets gate did not approve",
|
|
6306
|
+
ratchets: ratchets || null,
|
|
6307
|
+
consensus: null
|
|
6308
|
+
};
|
|
6309
|
+
}
|
|
6310
|
+
const consensus = await verify({
|
|
6311
|
+
task_id: taskId,
|
|
6312
|
+
gate_type: CONSENSUS_GATE_TYPE,
|
|
6313
|
+
excerpt: `${buildContractSummary(contract, tier)}
|
|
6314
|
+
|
|
6315
|
+
--- TEST ---
|
|
6316
|
+
${testSource}`,
|
|
6317
|
+
question: consensusQuestion(tier)
|
|
6318
|
+
});
|
|
6319
|
+
const consensusBlocks = consensus?.available === true && consensus?.approved !== true;
|
|
6320
|
+
if (consensusBlocks) {
|
|
6321
|
+
return {
|
|
6322
|
+
ship: false,
|
|
6323
|
+
tier,
|
|
6324
|
+
tierLabel: label,
|
|
6325
|
+
stage: "consensus",
|
|
6326
|
+
reason: consensus?.reason || "consensus did not confirm verified-correct expected values",
|
|
6327
|
+
ratchets,
|
|
6328
|
+
consensus
|
|
6329
|
+
};
|
|
6330
|
+
}
|
|
6331
|
+
return {
|
|
6332
|
+
ship: true,
|
|
6333
|
+
tier,
|
|
6334
|
+
tierLabel: label,
|
|
6335
|
+
stage: "passed",
|
|
6336
|
+
reason: consensus?.available === true ? `Passed ratchets + consensus (${label}). ${rationale}` : `Passed ratchets; consensus unavailable so not blocking (${label}). ${rationale}`,
|
|
6337
|
+
ratchets,
|
|
6338
|
+
consensus
|
|
6339
|
+
};
|
|
6340
|
+
}
|
|
6341
|
+
function makeHttpVerify({ baseUrl, token: token2, fetchImpl = fetch }) {
|
|
6342
|
+
if (!baseUrl) throw new Error("makeHttpVerify requires a baseUrl");
|
|
6343
|
+
const url = `${baseUrl.replace(/\/$/, "")}/api/v1/verify`;
|
|
6344
|
+
return async function httpVerify(req) {
|
|
6345
|
+
let res;
|
|
6346
|
+
try {
|
|
6347
|
+
res = await fetchImpl(url, {
|
|
6348
|
+
method: "POST",
|
|
6349
|
+
headers: { "Content-Type": "application/json", ...token2 ? { Authorization: `Bearer ${token2}` } : {} },
|
|
6350
|
+
body: JSON.stringify(req)
|
|
6351
|
+
});
|
|
6352
|
+
} catch (err) {
|
|
6353
|
+
return { ok: false, available: false, approved: false, reason: `transport error: ${err?.message || err}` };
|
|
6354
|
+
}
|
|
6355
|
+
let body = {};
|
|
6356
|
+
try {
|
|
6357
|
+
body = await res.json();
|
|
6358
|
+
} catch {
|
|
6359
|
+
}
|
|
6360
|
+
if (!res.ok) {
|
|
6361
|
+
return { ok: false, available: false, approved: false, reason: body?.error || `http ${res.status}` };
|
|
6362
|
+
}
|
|
6363
|
+
return body;
|
|
6364
|
+
};
|
|
6365
|
+
}
|
|
6366
|
+
var CONSENSUS_GATE_TYPE;
|
|
6367
|
+
var init_executor = __esm({
|
|
6368
|
+
"../../scripts/virtual-office/test-gen/executor.mjs"() {
|
|
6369
|
+
"use strict";
|
|
6370
|
+
init_auto_tier();
|
|
6371
|
+
CONSENSUS_GATE_TYPE = "test_correctness_consensus";
|
|
6372
|
+
}
|
|
6373
|
+
});
|
|
6374
|
+
|
|
6375
|
+
// ../../scripts/virtual-office/code-runner/test-gen-gate.mjs
|
|
6376
|
+
import fs7 from "node:fs";
|
|
6377
|
+
import path15 from "node:path";
|
|
6378
|
+
async function postFailed(client, id, message, result) {
|
|
6379
|
+
try {
|
|
6380
|
+
await client.postProgress(id, {
|
|
6381
|
+
status: "failed",
|
|
6382
|
+
message: String(message).slice(0, 1500),
|
|
6383
|
+
result
|
|
6384
|
+
});
|
|
6385
|
+
} catch {
|
|
6386
|
+
}
|
|
6387
|
+
}
|
|
6388
|
+
async function gateTestGenTaskOrFail({ client, id, task, files, worktreeDir, env: env2 = process.env, log: log2 = () => {
|
|
6389
|
+
}, verify: verifyInjected } = {}) {
|
|
6390
|
+
const prompt = String(task && task.prompt || "");
|
|
6391
|
+
if (!prompt.startsWith(TEST_GEN_MARKER)) return false;
|
|
6392
|
+
let contract;
|
|
6393
|
+
try {
|
|
6394
|
+
const after = prompt.slice(TEST_GEN_MARKER.length).trimStart();
|
|
6395
|
+
contract = JSON.parse(after.split("\n\n")[0]);
|
|
6396
|
+
} catch (err) {
|
|
6397
|
+
log2(`task ${id}: test-gen contract parse failed: ${err.message}`);
|
|
6398
|
+
await postFailed(client, id, `test-gen contract parse failed: ${err.message}`, "gate_contract_unparseable");
|
|
6399
|
+
return true;
|
|
6400
|
+
}
|
|
6401
|
+
const testFile = (files || []).find((f) => TEST_FILE_RE.test(f));
|
|
6402
|
+
if (!testFile) {
|
|
6403
|
+
await postFailed(client, id, "test-gen task produced no *.test.* file", "gate_no_test_file");
|
|
6404
|
+
return true;
|
|
6405
|
+
}
|
|
6406
|
+
const baseUrl = env2.VO_MOAT_PLANE_URL;
|
|
6407
|
+
if (!verifyInjected && !baseUrl) {
|
|
6408
|
+
log2(`task ${id}: VO_MOAT_PLANE_URL unset \u2014 skipping test-gen gate (fail-safe, ADR-002 opt-out)`);
|
|
6409
|
+
return false;
|
|
6410
|
+
}
|
|
6411
|
+
let testSource = "";
|
|
6412
|
+
try {
|
|
6413
|
+
testSource = fs7.readFileSync(path15.join(worktreeDir, testFile), "utf8");
|
|
6414
|
+
} catch (err) {
|
|
6415
|
+
await postFailed(client, id, `could not read generated test ${testFile}: ${err.message}`, "gate_test_unreadable");
|
|
6416
|
+
return true;
|
|
6417
|
+
}
|
|
6418
|
+
const verify = verifyInjected || makeHttpVerify({ baseUrl: String(baseUrl).replace(/\/$/, ""), token: env2.VO_MOAT_PLANE_TOKEN || "" });
|
|
6419
|
+
let verdict;
|
|
6420
|
+
try {
|
|
6421
|
+
verdict = await gateGeneratedTest({
|
|
6422
|
+
contract: { ...contract, test_filename: testFile },
|
|
6423
|
+
testSource,
|
|
6424
|
+
verify,
|
|
6425
|
+
taskId: id
|
|
6426
|
+
});
|
|
6427
|
+
} catch (err) {
|
|
6428
|
+
log2(`task ${id}: test-gen gate could not run: ${err.message}`);
|
|
6429
|
+
await postFailed(client, id, `test-gen gate could not run (${err.message}) \u2014 not shipping un-gated`, "gate_transport_error");
|
|
6430
|
+
return true;
|
|
6431
|
+
}
|
|
6432
|
+
if (!verdict.ship) {
|
|
6433
|
+
log2(`task ${id}: test-gen gate REJECTED at ${verdict.stage}`);
|
|
6434
|
+
await postFailed(
|
|
6435
|
+
client,
|
|
6436
|
+
id,
|
|
6437
|
+
`test-gen gate rejected (${verdict.stage}): ${verdict.reason || "did not pass ratchets + consensus"}`,
|
|
6438
|
+
"gate_rejected"
|
|
6439
|
+
);
|
|
6440
|
+
return true;
|
|
6441
|
+
}
|
|
6442
|
+
try {
|
|
6443
|
+
await client.postProgress(id, {
|
|
6444
|
+
message: `test-gen gate PASSED (${verdict.tierLabel || "tier"}): ${verdict.reason || "ratchets + consensus"}`
|
|
6445
|
+
});
|
|
6446
|
+
} catch {
|
|
6447
|
+
}
|
|
6448
|
+
return false;
|
|
6449
|
+
}
|
|
6450
|
+
var TEST_FILE_RE;
|
|
6451
|
+
var init_test_gen_gate = __esm({
|
|
6452
|
+
"../../scripts/virtual-office/code-runner/test-gen-gate.mjs"() {
|
|
6453
|
+
"use strict";
|
|
6454
|
+
init_dispatch();
|
|
6455
|
+
init_executor();
|
|
6456
|
+
TEST_FILE_RE = /\.(test|spec)\.(ts|tsx|mjs|js)$/;
|
|
6457
|
+
}
|
|
6458
|
+
});
|
|
6459
|
+
|
|
6460
|
+
// ../../scripts/virtual-office/code-runner/completion-gate.mjs
|
|
6461
|
+
import { execFile } from "node:child_process";
|
|
6462
|
+
import fs8 from "node:fs";
|
|
6463
|
+
import path16 from "node:path";
|
|
6464
|
+
function resolveCompletionGate(task) {
|
|
6465
|
+
const raw = task?.completion_gate;
|
|
6466
|
+
if (raw === void 0 || raw === null) return null;
|
|
6467
|
+
if (typeof raw !== "string" || raw.trim() === "") {
|
|
6468
|
+
return { invalid: true, reason: "completion_gate must be a non-empty string" };
|
|
6469
|
+
}
|
|
6470
|
+
const trimmed = raw.trim();
|
|
6471
|
+
if (trimmed.length > 500) {
|
|
6472
|
+
return { invalid: true, reason: "completion_gate exceeds 500 characters" };
|
|
6473
|
+
}
|
|
6474
|
+
if (SHELL_METACHARACTERS.test(trimmed)) {
|
|
6475
|
+
return { invalid: true, reason: "completion_gate contains shell metacharacters (no-shell contract: plain argv only, no pipes/redirects/quotes)" };
|
|
6476
|
+
}
|
|
6477
|
+
const [command, ...args] = trimmed.split(/\s+/);
|
|
6478
|
+
const allowedCommand = ALLOWED_GATE_COMMANDS.get(command);
|
|
6479
|
+
if (allowedCommand === void 0) {
|
|
6480
|
+
const shown = command.length > 40 ? `${command.slice(0, 40)}...` : command;
|
|
6481
|
+
return {
|
|
6482
|
+
invalid: true,
|
|
6483
|
+
reason: `completion_gate command ${shown} is not an allowed gate runner (${[...ALLOWED_GATE_COMMANDS.keys()].join(", ")})`
|
|
6484
|
+
};
|
|
6485
|
+
}
|
|
6486
|
+
return { argv: [allowedCommand, ...args] };
|
|
6487
|
+
}
|
|
6488
|
+
function boundedTail(text) {
|
|
6489
|
+
const s = String(text ?? "");
|
|
6490
|
+
return s.length <= COMPLETION_GATE_OUTPUT_CAP ? s : s.slice(s.length - COMPLETION_GATE_OUTPUT_CAP);
|
|
6491
|
+
}
|
|
6492
|
+
function workspaceFingerprint(worktreeDir, execFileImpl = execFile) {
|
|
6493
|
+
return new Promise((resolve2) => {
|
|
6494
|
+
execFileImpl("git", ["rev-parse", "HEAD^{tree}"], { cwd: worktreeDir }, (err, stdout) => {
|
|
6495
|
+
resolve2(err ? null : String(stdout).trim() || null);
|
|
6496
|
+
});
|
|
6497
|
+
});
|
|
6498
|
+
}
|
|
6499
|
+
function readState(worktreeDir) {
|
|
6500
|
+
try {
|
|
6501
|
+
return JSON.parse(fs8.readFileSync(path16.join(worktreeDir, COMPLETION_GATE_STATE_FILE), "utf8"));
|
|
6502
|
+
} catch {
|
|
6503
|
+
return null;
|
|
6504
|
+
}
|
|
6505
|
+
}
|
|
6506
|
+
function writeState(worktreeDir, state) {
|
|
6507
|
+
try {
|
|
6508
|
+
fs8.writeFileSync(path16.join(worktreeDir, COMPLETION_GATE_STATE_FILE), `${JSON.stringify(state)}
|
|
6509
|
+
`, "utf8");
|
|
6510
|
+
} catch {
|
|
6511
|
+
}
|
|
6512
|
+
}
|
|
6513
|
+
function runGateCommand({ argv, worktreeDir, timeoutMs = COMPLETION_GATE_TIMEOUT_MS, execFileImpl = execFile }) {
|
|
6514
|
+
return new Promise((resolve2) => {
|
|
6515
|
+
const command = ALLOWED_GATE_COMMANDS.get(argv?.[0]);
|
|
6516
|
+
if (command === void 0) {
|
|
6517
|
+
return resolve2({
|
|
6518
|
+
exitCode: 1,
|
|
6519
|
+
output: `completion_gate executable is not an allowed gate runner (${[...ALLOWED_GATE_COMMANDS.keys()].join(", ")})`,
|
|
6520
|
+
timedOut: false
|
|
6521
|
+
});
|
|
6522
|
+
}
|
|
6523
|
+
execFileImpl(
|
|
6524
|
+
command,
|
|
6525
|
+
argv.slice(1),
|
|
6526
|
+
{ cwd: worktreeDir, timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024, windowsHide: true },
|
|
6527
|
+
(err, stdout, stderr) => {
|
|
6528
|
+
const output = boundedTail(`${stdout ?? ""}
|
|
6529
|
+
${stderr ?? ""}`.trim());
|
|
6530
|
+
if (!err) return resolve2({ exitCode: 0, output, timedOut: false });
|
|
6531
|
+
const timedOut = err.killed === true || err.signal === "SIGTERM";
|
|
6532
|
+
const exitCode = typeof err.code === "number" ? err.code : 1;
|
|
6533
|
+
resolve2({ exitCode, output: output || boundedTail(err.message), timedOut });
|
|
6534
|
+
}
|
|
6535
|
+
);
|
|
6536
|
+
});
|
|
6537
|
+
}
|
|
6538
|
+
async function postFailed2(client, id, message, result) {
|
|
6539
|
+
try {
|
|
6540
|
+
await client.postProgress(id, { status: "failed", message: String(message).slice(0, 1500), result });
|
|
6541
|
+
} catch {
|
|
6542
|
+
}
|
|
6543
|
+
}
|
|
6544
|
+
function messageExcerpt(output) {
|
|
6545
|
+
const s = String(output ?? "");
|
|
6546
|
+
return s.length > 1200 ? `...${s.slice(-1200)}` : s;
|
|
6547
|
+
}
|
|
6548
|
+
async function enforceCompletionGateOrFail({ client, id, task, worktreeDir, log: log2 = () => {
|
|
6549
|
+
}, execFileImpl = execFile } = {}) {
|
|
6550
|
+
const resolved = resolveCompletionGate(task);
|
|
6551
|
+
if (resolved === null) return false;
|
|
6552
|
+
if (resolved.invalid) {
|
|
6553
|
+
log2(`task ${id}: completion_gate invalid \u2014 ${resolved.reason}`);
|
|
6554
|
+
await postFailed2(client, id, `completion_gate invalid (${resolved.reason}) \u2014 failing closed, not publishing`, "completion_gate_invalid");
|
|
6555
|
+
return true;
|
|
6556
|
+
}
|
|
6557
|
+
const fingerprint = await workspaceFingerprint(worktreeDir, execFileImpl);
|
|
6558
|
+
const cached2 = readState(worktreeDir);
|
|
6559
|
+
if (fingerprint && cached2 && cached2.fingerprint === fingerprint && cached2.exitCode !== 0) {
|
|
6560
|
+
log2(`task ${id}: completion gate skip-on-unchanged (tree ${fingerprint.slice(0, 12)}) \u2014 reusing recorded failure exit ${cached2.exitCode}`);
|
|
6561
|
+
await postFailed2(client, id, `completion gate '${task.completion_gate}' previously failed (exit ${cached2.exitCode}) and the workspace is unchanged:
|
|
6562
|
+
${messageExcerpt(cached2.output)}`, "completion_gate_failed");
|
|
6563
|
+
return true;
|
|
6564
|
+
}
|
|
6565
|
+
log2(`task ${id}: running completion gate: ${resolved.argv.join(" ")}`);
|
|
6566
|
+
const outcome = await runGateCommand({ argv: resolved.argv, worktreeDir, execFileImpl });
|
|
6567
|
+
if (fingerprint) writeState(worktreeDir, { fingerprint, exitCode: outcome.exitCode, output: outcome.output, at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
6568
|
+
if (outcome.exitCode === 0) {
|
|
6569
|
+
log2(`task ${id}: completion gate PASSED`);
|
|
6570
|
+
return false;
|
|
6571
|
+
}
|
|
6572
|
+
const kind = outcome.timedOut ? `timed out after ${COMPLETION_GATE_TIMEOUT_MS}ms` : `exited ${outcome.exitCode}`;
|
|
6573
|
+
log2(`task ${id}: completion gate FAILED (${kind}) \u2014 not publishing`);
|
|
6574
|
+
await postFailed2(client, id, `completion gate '${task.completion_gate}' ${kind} \u2014 task may not claim completion:
|
|
6575
|
+
${messageExcerpt(outcome.output)}`, "completion_gate_failed");
|
|
6576
|
+
return true;
|
|
6577
|
+
}
|
|
6578
|
+
var COMPLETION_GATE_TIMEOUT_MS, COMPLETION_GATE_OUTPUT_CAP, COMPLETION_GATE_STATE_FILE, SHELL_METACHARACTERS, ALLOWED_GATE_COMMANDS;
|
|
6579
|
+
var init_completion_gate = __esm({
|
|
6580
|
+
"../../scripts/virtual-office/code-runner/completion-gate.mjs"() {
|
|
6581
|
+
"use strict";
|
|
6582
|
+
COMPLETION_GATE_TIMEOUT_MS = 5 * 6e4;
|
|
6583
|
+
COMPLETION_GATE_OUTPUT_CAP = 8 * 1024;
|
|
6584
|
+
COMPLETION_GATE_STATE_FILE = ".vo-completion-gate-state.json";
|
|
6585
|
+
SHELL_METACHARACTERS = /[|&;<>$`(){}[\]*?~#\\'"]/;
|
|
6586
|
+
ALLOWED_GATE_COMMANDS = new Map(
|
|
6587
|
+
["pnpm", "npm", "yarn", "node", "git", "make", "python", "python3", "cargo", "go"].map((name) => [name, name])
|
|
6588
|
+
);
|
|
6589
|
+
}
|
|
6590
|
+
});
|
|
6591
|
+
|
|
5848
6592
|
// ../../scripts/virtual-office/code-runner/process-runner.mjs
|
|
5849
6593
|
import { spawn as spawn3 } from "node:child_process";
|
|
5850
6594
|
function buildStepLabel(cmd, args = []) {
|
|
@@ -6338,8 +7082,8 @@ var init_publish_async = __esm({
|
|
|
6338
7082
|
|
|
6339
7083
|
// ../../scripts/virtual-office/code-runner/skill-catalog.mjs
|
|
6340
7084
|
import { readdirSync as readdirSync2, readFileSync as readFileSync3, statSync } from "node:fs";
|
|
6341
|
-
import { dirname as
|
|
6342
|
-
import { fileURLToPath as
|
|
7085
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
7086
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
6343
7087
|
function parseFrontmatterNameDescription(raw) {
|
|
6344
7088
|
const text = String(raw).replace(/\r\n/g, "\n");
|
|
6345
7089
|
if (!text.startsWith("---\n")) return null;
|
|
@@ -6358,15 +7102,15 @@ function parseFrontmatterNameDescription(raw) {
|
|
|
6358
7102
|
return name && description ? { name, description } : null;
|
|
6359
7103
|
}
|
|
6360
7104
|
function resolveDefaultRepoRoot() {
|
|
6361
|
-
const starts = [
|
|
7105
|
+
const starts = [dirname3(fileURLToPath4(import.meta.url)), process.cwd()];
|
|
6362
7106
|
for (const start of starts) {
|
|
6363
7107
|
let dir = start;
|
|
6364
7108
|
for (let i = 0; i < 8; i += 1) {
|
|
6365
7109
|
try {
|
|
6366
|
-
if (statSync(
|
|
7110
|
+
if (statSync(join4(dir, ".claude", "skills")).isDirectory()) return dir;
|
|
6367
7111
|
} catch {
|
|
6368
7112
|
}
|
|
6369
|
-
const parent =
|
|
7113
|
+
const parent = dirname3(dir);
|
|
6370
7114
|
if (parent === dir) break;
|
|
6371
7115
|
dir = parent;
|
|
6372
7116
|
}
|
|
@@ -6375,14 +7119,14 @@ function resolveDefaultRepoRoot() {
|
|
|
6375
7119
|
}
|
|
6376
7120
|
function loadSkillCatalog({ repoRoot: repoRoot2 = resolveDefaultRepoRoot() } = {}) {
|
|
6377
7121
|
try {
|
|
6378
|
-
const skillsDir =
|
|
7122
|
+
const skillsDir = join4(repoRoot2, ".claude", "skills");
|
|
6379
7123
|
const catalog = [];
|
|
6380
7124
|
for (const entry of readdirSync2(skillsDir)) {
|
|
6381
|
-
const dir =
|
|
7125
|
+
const dir = join4(skillsDir, entry);
|
|
6382
7126
|
try {
|
|
6383
7127
|
if (!statSync(dir).isDirectory()) continue;
|
|
6384
7128
|
const parsed = parseFrontmatterNameDescription(
|
|
6385
|
-
readFileSync3(
|
|
7129
|
+
readFileSync3(join4(dir, "SKILL.md"), "utf8")
|
|
6386
7130
|
);
|
|
6387
7131
|
if (parsed) catalog.push(parsed);
|
|
6388
7132
|
} catch {
|
|
@@ -6614,7 +7358,7 @@ var init_task_prompt = __esm({
|
|
|
6614
7358
|
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
6615
7359
|
import { chmod, mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
6616
7360
|
import os2 from "node:os";
|
|
6617
|
-
import
|
|
7361
|
+
import path17 from "node:path";
|
|
6618
7362
|
function safeTaskToken(taskId) {
|
|
6619
7363
|
return String(taskId || "task").replace(/[^0-9A-Za-z_-]/gu, "_").slice(0, 48) || "task";
|
|
6620
7364
|
}
|
|
@@ -6624,25 +7368,25 @@ function sanitizeTaskAttachmentName(name, index = 0) {
|
|
|
6624
7368
|
return `${String(index + 1).padStart(2, "0")}-${normalized}`;
|
|
6625
7369
|
}
|
|
6626
7370
|
function assertGeneratedDirectory(directory, tempRoot) {
|
|
6627
|
-
const resolvedDirectory =
|
|
6628
|
-
const resolvedRoot =
|
|
6629
|
-
if (
|
|
7371
|
+
const resolvedDirectory = path17.resolve(directory);
|
|
7372
|
+
const resolvedRoot = path17.resolve(tempRoot);
|
|
7373
|
+
if (path17.dirname(resolvedDirectory) !== resolvedRoot || !path17.basename(resolvedDirectory).startsWith(DIRECTORY_PREFIX)) {
|
|
6630
7374
|
throw new Error("refusing to clean an unverified task-attachment directory");
|
|
6631
7375
|
}
|
|
6632
7376
|
return resolvedDirectory;
|
|
6633
7377
|
}
|
|
6634
7378
|
async function createAttachmentDirectory(taskId, tempRoot) {
|
|
6635
|
-
const root =
|
|
7379
|
+
const root = path17.resolve(tempRoot);
|
|
6636
7380
|
await mkdir(root, { recursive: true });
|
|
6637
|
-
const directory = await mkdtemp(
|
|
6638
|
-
const marker = JSON.stringify({ owner: MARKER_OWNER, token: randomUUID2(), directory:
|
|
6639
|
-
await writeFile(
|
|
7381
|
+
const directory = await mkdtemp(path17.join(root, `${DIRECTORY_PREFIX}${safeTaskToken(taskId)}-`));
|
|
7382
|
+
const marker = JSON.stringify({ owner: MARKER_OWNER, token: randomUUID2(), directory: path17.basename(directory), created_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
7383
|
+
await writeFile(path17.join(directory, MARKER_FILE), marker, { encoding: "utf8", mode: 384 });
|
|
6640
7384
|
return { directory, marker, tempRoot: root };
|
|
6641
7385
|
}
|
|
6642
7386
|
async function cleanupGeneratedDirectory(state) {
|
|
6643
7387
|
if (!state || state.cleaned) return;
|
|
6644
7388
|
const directory = assertGeneratedDirectory(state.directory, state.tempRoot);
|
|
6645
|
-
const marker = await readFile(
|
|
7389
|
+
const marker = await readFile(path17.join(directory, MARKER_FILE), "utf8").catch(() => "");
|
|
6646
7390
|
if (marker !== state.marker) throw new Error("refusing to clean a task-attachment directory without its exact marker");
|
|
6647
7391
|
await rm(directory, { recursive: true, force: true });
|
|
6648
7392
|
state.cleaned = true;
|
|
@@ -6661,7 +7405,7 @@ async function sweepStaleTaskAttachmentDirectories({
|
|
|
6661
7405
|
now = Date.now(),
|
|
6662
7406
|
maxAgeMs = DEFAULT_STALE_AGE_MS
|
|
6663
7407
|
} = {}) {
|
|
6664
|
-
const root =
|
|
7408
|
+
const root = path17.resolve(tempRoot);
|
|
6665
7409
|
if (!Number.isFinite(maxAgeMs) || maxAgeMs <= 0) throw new Error("stale attachment age must be positive");
|
|
6666
7410
|
const entries = await readdir(root, { withFileTypes: true }).catch((error) => {
|
|
6667
7411
|
if (error?.code === "ENOENT") return [];
|
|
@@ -6670,8 +7414,8 @@ async function sweepStaleTaskAttachmentDirectories({
|
|
|
6670
7414
|
let removed = 0;
|
|
6671
7415
|
for (const entry of entries) {
|
|
6672
7416
|
if (!entry.isDirectory() || !entry.name.startsWith(DIRECTORY_PREFIX)) continue;
|
|
6673
|
-
const directory = assertGeneratedDirectory(
|
|
6674
|
-
const markerRaw = await readFile(
|
|
7417
|
+
const directory = assertGeneratedDirectory(path17.join(root, entry.name), root);
|
|
7418
|
+
const markerRaw = await readFile(path17.join(directory, MARKER_FILE), "utf8").catch(() => "");
|
|
6675
7419
|
const marker = parseOwnedMarker(markerRaw, entry.name);
|
|
6676
7420
|
if (!marker) continue;
|
|
6677
7421
|
const directoryStat = await stat(directory);
|
|
@@ -6714,10 +7458,10 @@ async function materializeTaskAttachments(client, task, { tempRoot = os2.tmpdir(
|
|
|
6714
7458
|
const sha256 = createHash3("sha256").update(content).digest("hex");
|
|
6715
7459
|
if (sha256 !== ref.sha256) throw new Error(`attachment ${ref.attachment_id} sha256 mismatch`);
|
|
6716
7460
|
const name = sanitizeTaskAttachmentName(ref.name, index);
|
|
6717
|
-
const filePath =
|
|
7461
|
+
const filePath = path17.join(state.directory, name);
|
|
6718
7462
|
await writeFile(filePath, content, { flag: "wx", mode: 384 });
|
|
6719
7463
|
await chmod(filePath, 384);
|
|
6720
|
-
files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path:
|
|
7464
|
+
files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path: path17.resolve(filePath) });
|
|
6721
7465
|
}
|
|
6722
7466
|
return { directory: state.directory, files, manifestMarkdown: buildManifest(files), cleanup: () => cleanupGeneratedDirectory(state) };
|
|
6723
7467
|
} catch (error) {
|
|
@@ -6740,7 +7484,7 @@ var init_task_attachments = __esm({
|
|
|
6740
7484
|
|
|
6741
7485
|
// ../../scripts/virtual-office/code-runner/session-spool-forwarder.mjs
|
|
6742
7486
|
import { homedir as homedir4 } from "node:os";
|
|
6743
|
-
import { join as
|
|
7487
|
+
import { join as join5 } from "node:path";
|
|
6744
7488
|
import { readdir as readdir2, readFile as readFile2, unlink, writeFile as writeFile2 } from "node:fs/promises";
|
|
6745
7489
|
import { createHash as createHash4 } from "node:crypto";
|
|
6746
7490
|
function deriveUuid(seed) {
|
|
@@ -6772,18 +7516,18 @@ async function readSpool(spoolDir = SPOOL_DIR) {
|
|
|
6772
7516
|
for (const f of files) {
|
|
6773
7517
|
if (!f.endsWith(".json")) continue;
|
|
6774
7518
|
try {
|
|
6775
|
-
const record = JSON.parse(await readFile2(
|
|
7519
|
+
const record = JSON.parse(await readFile2(join5(spoolDir, f), "utf8"));
|
|
6776
7520
|
if (record && typeof record.session_key === "string") {
|
|
6777
|
-
out.push({ full:
|
|
7521
|
+
out.push({ full: join5(spoolDir, f), record });
|
|
6778
7522
|
}
|
|
6779
7523
|
} catch {
|
|
6780
7524
|
}
|
|
6781
7525
|
}
|
|
6782
7526
|
return out;
|
|
6783
7527
|
}
|
|
6784
|
-
async function readCloudMap(
|
|
7528
|
+
async function readCloudMap(path23) {
|
|
6785
7529
|
try {
|
|
6786
|
-
return JSON.parse(await readFile2(
|
|
7530
|
+
return JSON.parse(await readFile2(path23, "utf8"));
|
|
6787
7531
|
} catch {
|
|
6788
7532
|
return {};
|
|
6789
7533
|
}
|
|
@@ -6856,8 +7600,8 @@ var SPOOL_DIR, CLOUD_MAP_FILE, STALE_MS, ACTIVE_SILENCE_MS;
|
|
|
6856
7600
|
var init_session_spool_forwarder = __esm({
|
|
6857
7601
|
"../../scripts/virtual-office/code-runner/session-spool-forwarder.mjs"() {
|
|
6858
7602
|
"use strict";
|
|
6859
|
-
SPOOL_DIR =
|
|
6860
|
-
CLOUD_MAP_FILE =
|
|
7603
|
+
SPOOL_DIR = join5(homedir4(), ".vo", "session-spool");
|
|
7604
|
+
CLOUD_MAP_FILE = join5(homedir4(), ".vo", "session-cloud-map.json");
|
|
6861
7605
|
STALE_MS = 60 * 60 * 1e3;
|
|
6862
7606
|
ACTIVE_SILENCE_MS = 10 * 60 * 1e3;
|
|
6863
7607
|
}
|
|
@@ -6928,7 +7672,7 @@ var init_rate_limit_resume_scheduler_core = __esm({
|
|
|
6928
7672
|
});
|
|
6929
7673
|
|
|
6930
7674
|
// ../../scripts/virtual-office/code-runner/rate-limit-resume-scheduler.mjs
|
|
6931
|
-
import { dirname as
|
|
7675
|
+
import { dirname as dirname4, join as join6, resolve } from "node:path";
|
|
6932
7676
|
function defaultLog(message) {
|
|
6933
7677
|
console.log(`[rate-limit-scheduler ${(/* @__PURE__ */ new Date()).toISOString()}] ${message}`);
|
|
6934
7678
|
}
|
|
@@ -7010,7 +7754,7 @@ async function runLockedScheduler({
|
|
|
7010
7754
|
async function runScheduler({
|
|
7011
7755
|
env: env2 = process.env,
|
|
7012
7756
|
queuePath = resumeQueuePath(),
|
|
7013
|
-
attemptsPath =
|
|
7757
|
+
attemptsPath = join6(dirname4(queuePath), "resume-attempts.json"),
|
|
7014
7758
|
client,
|
|
7015
7759
|
now,
|
|
7016
7760
|
log: log2 = defaultLog
|
|
@@ -7073,6 +7817,10 @@ function makeLoopTicks({
|
|
|
7073
7817
|
applyRemoteConfig: () => false,
|
|
7074
7818
|
heartbeatFields: () => ({})
|
|
7075
7819
|
},
|
|
7820
|
+
// Host version awareness: reads `update_status` off the heartbeat ACK and logs
|
|
7821
|
+
// ONE line per drift change (daemon-update-status.mjs). No-op default keeps
|
|
7822
|
+
// old callers working; absent update_status reads as unknown, never current.
|
|
7823
|
+
updateStatusTracker = { applyHeartbeatResponse: () => false },
|
|
7076
7824
|
// Cached agent-availability provider (agent-availability.mjs); returns null
|
|
7077
7825
|
// until the first probe completes — the heartbeat simply omits the field.
|
|
7078
7826
|
getAgentAvailability = () => null,
|
|
@@ -7113,6 +7861,7 @@ function makeLoopTicks({
|
|
|
7113
7861
|
request.then((response) => {
|
|
7114
7862
|
capacityController.applyCapacity(response?.capacity, nextPayload.operatorId);
|
|
7115
7863
|
localModelController.applyRemoteConfig(response?.local_model, nextPayload.operatorId);
|
|
7864
|
+
updateStatusTracker.applyHeartbeatResponse(response);
|
|
7116
7865
|
}).catch((e) => log2(`heartbeat failed: ${e.message}`)).finally(() => {
|
|
7117
7866
|
for (const done of waiters) done();
|
|
7118
7867
|
if (state.pending) {
|
|
@@ -7302,7 +8051,7 @@ var init_runner_capacity = __esm({
|
|
|
7302
8051
|
});
|
|
7303
8052
|
|
|
7304
8053
|
// ../../scripts/virtual-office/code-runner/agent-auth-probe-process.mjs
|
|
7305
|
-
import { fileURLToPath as
|
|
8054
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
7306
8055
|
async function probeAgentInChild(agent, timeoutMs) {
|
|
7307
8056
|
const stdout = await runProcess2(process.execPath, [probeCli, agent], {
|
|
7308
8057
|
timeout: timeoutMs,
|
|
@@ -7315,7 +8064,7 @@ var init_agent_auth_probe_process = __esm({
|
|
|
7315
8064
|
"../../scripts/virtual-office/code-runner/agent-auth-probe-process.mjs"() {
|
|
7316
8065
|
"use strict";
|
|
7317
8066
|
init_process_runner2();
|
|
7318
|
-
probeCli =
|
|
8067
|
+
probeCli = fileURLToPath5(new URL("./agent-auth-probe-cli.mjs", import.meta.url));
|
|
7319
8068
|
}
|
|
7320
8069
|
});
|
|
7321
8070
|
|
|
@@ -7540,7 +8289,7 @@ var init_local_model_remote_config = __esm({
|
|
|
7540
8289
|
|
|
7541
8290
|
// ../../scripts/virtual-office/code-runner/account-usage/shared.mjs
|
|
7542
8291
|
import crypto from "node:crypto";
|
|
7543
|
-
import
|
|
8292
|
+
import fs9 from "node:fs";
|
|
7544
8293
|
function accountKey(agent, rawId) {
|
|
7545
8294
|
const id = typeof rawId === "string" ? rawId.trim() : "";
|
|
7546
8295
|
if (!id) return null;
|
|
@@ -7604,7 +8353,7 @@ var init_shared = __esm({
|
|
|
7604
8353
|
};
|
|
7605
8354
|
readJson = (p) => {
|
|
7606
8355
|
try {
|
|
7607
|
-
return JSON.parse(
|
|
8356
|
+
return JSON.parse(fs9.readFileSync(p, "utf8"));
|
|
7608
8357
|
} catch {
|
|
7609
8358
|
return null;
|
|
7610
8359
|
}
|
|
@@ -7614,9 +8363,9 @@ var init_shared = __esm({
|
|
|
7614
8363
|
});
|
|
7615
8364
|
|
|
7616
8365
|
// ../../scripts/virtual-office/code-runner/account-usage/claude.mjs
|
|
7617
|
-
import
|
|
8366
|
+
import fs10 from "node:fs";
|
|
7618
8367
|
import os3 from "node:os";
|
|
7619
|
-
import
|
|
8368
|
+
import path18 from "node:path";
|
|
7620
8369
|
function fileCaptureTime(filePath, explicit, statFn) {
|
|
7621
8370
|
if (typeof explicit === "string" && explicit) return explicit;
|
|
7622
8371
|
try {
|
|
@@ -7630,7 +8379,7 @@ function usageBaseUrl(env2 = process.env) {
|
|
|
7630
8379
|
return String(raw).replace(/\/+$/, "");
|
|
7631
8380
|
}
|
|
7632
8381
|
function readOAuthToken({ homeDir = os3.homedir(), read = readJson, now = Date.now() } = {}) {
|
|
7633
|
-
const creds = read(
|
|
8382
|
+
const creds = read(path18.join(homeDir, ".claude", ".credentials.json"));
|
|
7634
8383
|
const oauth = creds && typeof creds === "object" ? creds.claudeAiOauth : null;
|
|
7635
8384
|
if (!oauth || typeof oauth !== "object") return null;
|
|
7636
8385
|
const token2 = typeof oauth.accessToken === "string" ? oauth.accessToken.trim() : "";
|
|
@@ -7640,7 +8389,7 @@ function readOAuthToken({ homeDir = os3.homedir(), read = readJson, now = Date.n
|
|
|
7640
8389
|
return token2;
|
|
7641
8390
|
}
|
|
7642
8391
|
function readAccountId({ homeDir = os3.homedir(), read = readJson } = {}) {
|
|
7643
|
-
const cfg = read(
|
|
8392
|
+
const cfg = read(path18.join(homeDir, ".claude.json"));
|
|
7644
8393
|
const account = cfg && typeof cfg === "object" ? cfg.oauthAccount : null;
|
|
7645
8394
|
return account && typeof account.accountUuid === "string" ? account.accountUuid : null;
|
|
7646
8395
|
}
|
|
@@ -7733,7 +8482,7 @@ async function readClaudeOAuthUsage({
|
|
|
7733
8482
|
function readClaudeFileUsage({
|
|
7734
8483
|
homeDir = os3.homedir(),
|
|
7735
8484
|
read: rawRead = readJson,
|
|
7736
|
-
statFn =
|
|
8485
|
+
statFn = fs10.statSync,
|
|
7737
8486
|
now = () => Date.now()
|
|
7738
8487
|
} = {}) {
|
|
7739
8488
|
const read = (p) => {
|
|
@@ -7750,7 +8499,7 @@ function readClaudeFileUsage({
|
|
|
7750
8499
|
if (age === null || age > MAX_FILE_AGE_MS) return null;
|
|
7751
8500
|
return row;
|
|
7752
8501
|
};
|
|
7753
|
-
const statusPath =
|
|
8502
|
+
const statusPath = path18.join(homeDir, ".claude", "claude-usage.json");
|
|
7754
8503
|
const status = read(statusPath);
|
|
7755
8504
|
if (status && (status.seven_day || status.five_hour)) {
|
|
7756
8505
|
const row = fresh(makeUsageRow({
|
|
@@ -7765,7 +8514,7 @@ function readClaudeFileUsage({
|
|
|
7765
8514
|
}));
|
|
7766
8515
|
if (row) return row;
|
|
7767
8516
|
}
|
|
7768
|
-
const weeklyPath =
|
|
8517
|
+
const weeklyPath = path18.join(homeDir, ".claude", "claude-weekly-usage.json");
|
|
7769
8518
|
const weekly = read(weeklyPath);
|
|
7770
8519
|
if (weekly) {
|
|
7771
8520
|
const row = fresh(makeUsageRow({
|
|
@@ -8206,7 +8955,7 @@ var init_watcher_coordination = __esm({
|
|
|
8206
8955
|
// ../../scripts/virtual-office/code-runner/watcher-state.mjs
|
|
8207
8956
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
8208
8957
|
import { mkdir as mkdir2, open, readFile as readFile3, rename, unlink as unlink2 } from "node:fs/promises";
|
|
8209
|
-
import { dirname as
|
|
8958
|
+
import { dirname as dirname5 } from "node:path";
|
|
8210
8959
|
async function readWatcherState(stateFile) {
|
|
8211
8960
|
let raw;
|
|
8212
8961
|
try {
|
|
@@ -8222,7 +8971,7 @@ async function readWatcherState(stateFile) {
|
|
|
8222
8971
|
return parsed;
|
|
8223
8972
|
}
|
|
8224
8973
|
async function writeWatcherState(stateFile, state) {
|
|
8225
|
-
const directory =
|
|
8974
|
+
const directory = dirname5(stateFile);
|
|
8226
8975
|
await mkdir2(directory, { recursive: true });
|
|
8227
8976
|
const temp = `${stateFile}.${process.pid}.${randomUUID3()}.tmp`;
|
|
8228
8977
|
let handle;
|
|
@@ -8468,7 +9217,7 @@ var init_enqueue_autonomous_code_task = __esm({
|
|
|
8468
9217
|
|
|
8469
9218
|
// ../../scripts/virtual-office/code-runner/pr-watcher.mjs
|
|
8470
9219
|
import { homedir as homedir5 } from "node:os";
|
|
8471
|
-
import { join as
|
|
9220
|
+
import { join as join7 } from "node:path";
|
|
8472
9221
|
function parsePrCiStatus(view) {
|
|
8473
9222
|
const state = (view && typeof view.state === "string" ? view.state : "UNKNOWN").toUpperCase();
|
|
8474
9223
|
const rollup = view && Array.isArray(view.statusCheckRollup) ? view.statusCheckRollup : [];
|
|
@@ -8811,7 +9560,7 @@ var init_pr_watcher = __esm({
|
|
|
8811
9560
|
init_watcher_state();
|
|
8812
9561
|
init_superseded_pr_source();
|
|
8813
9562
|
init_ci_fix_prompt();
|
|
8814
|
-
DEFAULT_STATE_FILE =
|
|
9563
|
+
DEFAULT_STATE_FILE = join7(homedir5(), ".vo", "dispatched-prs.json");
|
|
8815
9564
|
FAIL_CONCLUSIONS = /* @__PURE__ */ new Set([
|
|
8816
9565
|
"FAILURE",
|
|
8817
9566
|
"TIMED_OUT",
|
|
@@ -9041,9 +9790,9 @@ function buildControlHandler({ getStatus, requestStop, allowedOrigin }) {
|
|
|
9041
9790
|
res.end();
|
|
9042
9791
|
return;
|
|
9043
9792
|
}
|
|
9044
|
-
const
|
|
9793
|
+
const path23 = String(req.url || "").split("?")[0];
|
|
9045
9794
|
res.setHeader("content-type", "application/json");
|
|
9046
|
-
if (req.method === "GET" &&
|
|
9795
|
+
if (req.method === "GET" && path23 === "/status") {
|
|
9047
9796
|
let status;
|
|
9048
9797
|
try {
|
|
9049
9798
|
status = getStatus();
|
|
@@ -9054,7 +9803,7 @@ function buildControlHandler({ getStatus, requestStop, allowedOrigin }) {
|
|
|
9054
9803
|
res.end(JSON.stringify({ ok: true, ...status }));
|
|
9055
9804
|
return;
|
|
9056
9805
|
}
|
|
9057
|
-
if (req.method === "POST" &&
|
|
9806
|
+
if (req.method === "POST" && path23 === "/stop") {
|
|
9058
9807
|
if (!isControlOriginAllowed(req.headers.origin, allowedOrigin) || !req.headers["x-vo-control"]) {
|
|
9059
9808
|
res.statusCode = 403;
|
|
9060
9809
|
res.end(JSON.stringify({ ok: false, error: "forbidden" }));
|
|
@@ -9115,7 +9864,7 @@ function startControlServer({ port, getStatus, requestStop, allowedOrigin, log:
|
|
|
9115
9864
|
return server;
|
|
9116
9865
|
}
|
|
9117
9866
|
function startDaemonControl({ cfg, runnerInstanceId, requestStop, getActiveCount, isRunning, startedAt, log: log2 = () => {
|
|
9118
|
-
}, onDuplicate = null }) {
|
|
9867
|
+
}, onDuplicate = null, getUpdateStatus = () => null }) {
|
|
9119
9868
|
if (!cfg.controlEnabled) return null;
|
|
9120
9869
|
return startControlServer({
|
|
9121
9870
|
port: cfg.controlPort,
|
|
@@ -9132,7 +9881,9 @@ function startDaemonControl({ cfg, runnerInstanceId, requestStop, getActiveCount
|
|
|
9132
9881
|
watchEnabled: cfg.watchEnabled,
|
|
9133
9882
|
activeTasks: getActiveCount(),
|
|
9134
9883
|
startedAt: new Date(startedAt).toISOString(),
|
|
9135
|
-
uptimeSec: Math.round((Date.now() - startedAt) / 1e3)
|
|
9884
|
+
uptimeSec: Math.round((Date.now() - startedAt) / 1e3),
|
|
9885
|
+
// Host version awareness — the app + `runner --status` read drift from here.
|
|
9886
|
+
updateStatus: getUpdateStatus()
|
|
9136
9887
|
}),
|
|
9137
9888
|
log: log2
|
|
9138
9889
|
});
|
|
@@ -9217,18 +9968,35 @@ var init_effort_mode_config = __esm({
|
|
|
9217
9968
|
});
|
|
9218
9969
|
|
|
9219
9970
|
// ../../scripts/virtual-office/model-registry.mjs
|
|
9220
|
-
import
|
|
9221
|
-
import
|
|
9222
|
-
import
|
|
9971
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
9972
|
+
import fs11 from "node:fs";
|
|
9973
|
+
import os4 from "node:os";
|
|
9974
|
+
import path19 from "node:path";
|
|
9975
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
9976
|
+
function userCacheRoot() {
|
|
9977
|
+
try {
|
|
9978
|
+
const home = os4.homedir();
|
|
9979
|
+
if (home) return path19.join(home, ".claude");
|
|
9980
|
+
} catch {
|
|
9981
|
+
}
|
|
9982
|
+
return path19.join(os4.tmpdir(), `vo-model-registry-${randomUUID5()}`);
|
|
9983
|
+
}
|
|
9984
|
+
function resolveCacheBaseDir(env2 = process.env, moduleDir = __dirname) {
|
|
9985
|
+
if (env2.VO_MODEL_REGISTRY_CACHE_DIR) return env2.VO_MODEL_REGISTRY_CACHE_DIR;
|
|
9986
|
+
if (env2.VO_RUNNER_RUNTIME_ROOT) return env2.VO_RUNNER_RUNTIME_ROOT;
|
|
9987
|
+
const segments = moduleDir.split(path19.sep);
|
|
9988
|
+
const isRepoCheckout = segments.at(-1) === "virtual-office" && segments.at(-2) === "scripts";
|
|
9989
|
+
return isRepoCheckout ? path19.resolve(moduleDir, "..", "..") : userCacheRoot();
|
|
9990
|
+
}
|
|
9223
9991
|
function uniqueModels(models = []) {
|
|
9224
9992
|
return [...new Set(models.map((model) => String(model || "").trim()).filter(Boolean))];
|
|
9225
9993
|
}
|
|
9226
9994
|
function normalizeProvider(value = "") {
|
|
9227
|
-
const
|
|
9228
|
-
if (
|
|
9229
|
-
if (
|
|
9230
|
-
if (
|
|
9231
|
-
return
|
|
9995
|
+
const lower2 = String(value || "").trim().toLowerCase();
|
|
9996
|
+
if (lower2.includes("anthropic")) return "anthropic";
|
|
9997
|
+
if (lower2.includes("openai")) return "openai";
|
|
9998
|
+
if (lower2.includes("google") || lower2.includes("gemini")) return "google";
|
|
9999
|
+
return lower2;
|
|
9232
10000
|
}
|
|
9233
10001
|
function stripProviderPrefix(id = "") {
|
|
9234
10002
|
const raw = String(id || "").trim();
|
|
@@ -9270,15 +10038,15 @@ function normalizeCatalogModel(model = {}) {
|
|
|
9270
10038
|
};
|
|
9271
10039
|
}
|
|
9272
10040
|
function parseVersionScore(id = "") {
|
|
9273
|
-
const
|
|
9274
|
-
const numbers = [...
|
|
10041
|
+
const lower2 = String(id || "").toLowerCase();
|
|
10042
|
+
const numbers = [...lower2.matchAll(/\d+/g)].map((match) => Number(match[0])).filter(Number.isFinite);
|
|
9275
10043
|
let score = 0;
|
|
9276
10044
|
for (let i = 0; i < numbers.length; i++) score += numbers[i] / Math.pow(1e3, i);
|
|
9277
|
-
if (/opus|pro|flagship/.test(
|
|
9278
|
-
if (/sonnet/.test(
|
|
9279
|
-
if (/preview|latest/.test(
|
|
9280
|
-
if (/\[1m\]|\(1m\)/i.test(
|
|
9281
|
-
if (/mini|nano|haiku|lite/.test(
|
|
10045
|
+
if (/opus|pro|flagship/.test(lower2)) score += 10;
|
|
10046
|
+
if (/sonnet/.test(lower2)) score += 5;
|
|
10047
|
+
if (/preview|latest/.test(lower2)) score += 0.25;
|
|
10048
|
+
if (/\[1m\]|\(1m\)/i.test(lower2)) score += 1;
|
|
10049
|
+
if (/mini|nano|haiku|lite/.test(lower2)) score -= 20;
|
|
9282
10050
|
return score;
|
|
9283
10051
|
}
|
|
9284
10052
|
function familyMatches(model, family) {
|
|
@@ -9330,9 +10098,9 @@ async function fetchGoogleModels(fetchImpl, env2 = process.env) {
|
|
|
9330
10098
|
return (data?.models || []).map((model) => normalizeCatalogModel({ ...model, provider: "google", source: "google" })).filter(Boolean);
|
|
9331
10099
|
}
|
|
9332
10100
|
function readCache(cacheFile = DEFAULT_CACHE_FILE, nowMs = Date.now(), ttlMs = DEFAULT_TTL_MS3) {
|
|
9333
|
-
if (!
|
|
10101
|
+
if (!fs11.existsSync(cacheFile)) return null;
|
|
9334
10102
|
try {
|
|
9335
|
-
const parsed = JSON.parse(
|
|
10103
|
+
const parsed = JSON.parse(fs11.readFileSync(cacheFile, "utf-8"));
|
|
9336
10104
|
if (nowMs - Number(parsed.checkedAtMs || 0) > ttlMs) return null;
|
|
9337
10105
|
if (!Array.isArray(parsed.models)) return null;
|
|
9338
10106
|
return parsed;
|
|
@@ -9341,8 +10109,8 @@ function readCache(cacheFile = DEFAULT_CACHE_FILE, nowMs = Date.now(), ttlMs = D
|
|
|
9341
10109
|
}
|
|
9342
10110
|
}
|
|
9343
10111
|
function writeCache(cacheFile = DEFAULT_CACHE_FILE, payload) {
|
|
9344
|
-
|
|
9345
|
-
|
|
10112
|
+
fs11.mkdirSync(path19.dirname(cacheFile), { recursive: true });
|
|
10113
|
+
fs11.writeFileSync(cacheFile, JSON.stringify(payload, null, 2));
|
|
9346
10114
|
}
|
|
9347
10115
|
async function fetchRegistryCatalog({
|
|
9348
10116
|
fetchImpl = fetch,
|
|
@@ -9395,14 +10163,17 @@ async function resolveModelFamily(family, options = {}) {
|
|
|
9395
10163
|
const resolved = selectBestFamilyModel(catalog.models || [], family);
|
|
9396
10164
|
return resolved || def.fallbacks[0];
|
|
9397
10165
|
}
|
|
9398
|
-
var __dirname,
|
|
10166
|
+
var __dirname, DEFAULT_CACHE_DIR, DEFAULT_CACHE_FILE, DEFAULT_TTL_MS3, ANTHROPIC_API_VERSION, FAMILY_DEFINITIONS, memoryCache;
|
|
9399
10167
|
var init_model_registry = __esm({
|
|
9400
10168
|
"../../scripts/virtual-office/model-registry.mjs"() {
|
|
9401
10169
|
"use strict";
|
|
9402
|
-
__dirname =
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
10170
|
+
__dirname = path19.dirname(fileURLToPath6(import.meta.url));
|
|
10171
|
+
DEFAULT_CACHE_DIR = path19.join(
|
|
10172
|
+
resolveCacheBaseDir(),
|
|
10173
|
+
".virtual-office-cache",
|
|
10174
|
+
"model-registry"
|
|
10175
|
+
);
|
|
10176
|
+
DEFAULT_CACHE_FILE = path19.join(DEFAULT_CACHE_DIR, "catalog.json");
|
|
9406
10177
|
DEFAULT_TTL_MS3 = 60 * 60 * 1e3;
|
|
9407
10178
|
ANTHROPIC_API_VERSION = "2023-06-01";
|
|
9408
10179
|
FAMILY_DEFINITIONS = {
|
|
@@ -9507,17 +10278,17 @@ function modelCompatibleWithAgent(agent, model) {
|
|
|
9507
10278
|
if (!model) return true;
|
|
9508
10279
|
return AGENT_MODEL_COMPATIBILITY[agent]?.(model) ?? false;
|
|
9509
10280
|
}
|
|
9510
|
-
function
|
|
10281
|
+
function classifyTier2(prompt) {
|
|
9511
10282
|
const text = String(prompt || "").trim();
|
|
9512
10283
|
if (!text) return "mid";
|
|
9513
|
-
const
|
|
10284
|
+
const lower2 = text.toLowerCase();
|
|
9514
10285
|
if (/lint|format|typo|missing import|update deps|chore|maintenance|runner|daemon/.test(
|
|
9515
|
-
|
|
10286
|
+
lower2
|
|
9516
10287
|
)) {
|
|
9517
10288
|
return "cheap";
|
|
9518
10289
|
}
|
|
9519
10290
|
if (/generate roadmap|new feature|implement .* feature|major refactor|strategic/.test(
|
|
9520
|
-
|
|
10291
|
+
lower2
|
|
9521
10292
|
) || text.length > 1500) {
|
|
9522
10293
|
return "best";
|
|
9523
10294
|
}
|
|
@@ -9538,7 +10309,7 @@ async function resolveModelForTier(tier, { agent = DEFAULT_AGENT2, resolveModelF
|
|
|
9538
10309
|
return fallbacks[effectiveTier];
|
|
9539
10310
|
}
|
|
9540
10311
|
async function resolveTaskModel(task, { agent = DEFAULT_AGENT2 } = {}) {
|
|
9541
|
-
const tier = task.tier && task.tier !== "auto" ? task.tier :
|
|
10312
|
+
const tier = task.tier && task.tier !== "auto" ? task.tier : classifyTier2(task.prompt);
|
|
9542
10313
|
const pinned = typeof task.model === "string" ? task.model.trim() : "";
|
|
9543
10314
|
if (pinned && modelCompatibleWithAgent(normalizeAgent(agent), pinned)) {
|
|
9544
10315
|
return { tier, model: pinned };
|
|
@@ -10011,7 +10782,7 @@ var init_classify_task = __esm({
|
|
|
10011
10782
|
// ../../scripts/virtual-office/code-runner/auto-router/effort-policy.mjs
|
|
10012
10783
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
10013
10784
|
import { homedir as homedir6 } from "node:os";
|
|
10014
|
-
import { join as
|
|
10785
|
+
import { join as join8 } from "node:path";
|
|
10015
10786
|
function difficultyToRung(difficulty, thresholds) {
|
|
10016
10787
|
const b = thresholds.rungBounds;
|
|
10017
10788
|
if (difficulty >= b.R5) return "R5";
|
|
@@ -10036,9 +10807,9 @@ function operatorTierToRung(tier, difficulty, thresholds) {
|
|
|
10036
10807
|
if (tier === "best" && difficulty >= thresholds.rungBounds.R5) return "R5";
|
|
10037
10808
|
return base;
|
|
10038
10809
|
}
|
|
10039
|
-
function readCodexModelsCache({ path:
|
|
10810
|
+
function readCodexModelsCache({ path: path23 = DEFAULT_CODEX_MODELS_CACHE, read = readFileSync4 } = {}) {
|
|
10040
10811
|
try {
|
|
10041
|
-
const parsed = JSON.parse(read(
|
|
10812
|
+
const parsed = JSON.parse(read(path23, "utf8"));
|
|
10042
10813
|
return Array.isArray(parsed?.models) ? parsed : null;
|
|
10043
10814
|
} catch {
|
|
10044
10815
|
return null;
|
|
@@ -10088,7 +10859,7 @@ var init_effort_policy = __esm({
|
|
|
10088
10859
|
init_meta_model_catalog();
|
|
10089
10860
|
RUNG_ORDER = ["R1", "R2", "R3", "R4", "R5"];
|
|
10090
10861
|
rungIndex = (rung) => RUNG_ORDER.indexOf(rung);
|
|
10091
|
-
DEFAULT_CODEX_MODELS_CACHE =
|
|
10862
|
+
DEFAULT_CODEX_MODELS_CACHE = join8(homedir6(), ".codex", "models_cache.json");
|
|
10092
10863
|
}
|
|
10093
10864
|
});
|
|
10094
10865
|
|
|
@@ -10220,16 +10991,16 @@ var init_role_cost_shadow = __esm({
|
|
|
10220
10991
|
// ../../scripts/virtual-office/code-runner/auto-router/auto-router.mjs
|
|
10221
10992
|
import { readFileSync as readFileSync5, appendFileSync, mkdirSync as mkdirSync4 } from "node:fs";
|
|
10222
10993
|
import { homedir as homedir7 } from "node:os";
|
|
10223
|
-
import { join as
|
|
10224
|
-
import { fileURLToPath as
|
|
10994
|
+
import { join as join9, dirname as dirname6 } from "node:path";
|
|
10995
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
10225
10996
|
function getAutoRouterMode(env2 = process.env) {
|
|
10226
10997
|
const raw = String(env2.VO_CODE_RUNNER_AUTO_ROUTER || "").trim().toLowerCase();
|
|
10227
10998
|
return MODES.has(raw) ? raw : "off";
|
|
10228
10999
|
}
|
|
10229
11000
|
function loadThresholds() {
|
|
10230
11001
|
if (!cachedThresholds) {
|
|
10231
|
-
const here =
|
|
10232
|
-
cachedThresholds = JSON.parse(readFileSync5(
|
|
11002
|
+
const here = dirname6(fileURLToPath7(import.meta.url));
|
|
11003
|
+
cachedThresholds = JSON.parse(readFileSync5(join9(here, "thresholds.json"), "utf8"));
|
|
10233
11004
|
}
|
|
10234
11005
|
return cachedThresholds;
|
|
10235
11006
|
}
|
|
@@ -10295,15 +11066,15 @@ function formatDecisionReason(decision, maxLen = 480) {
|
|
|
10295
11066
|
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("; ")}`;
|
|
10296
11067
|
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
10297
11068
|
}
|
|
10298
|
-
function appendDecisionFallback(decision, { path:
|
|
11069
|
+
function appendDecisionFallback(decision, { path: path23 = DECISION_FALLBACK_PATH, append = appendFileSync, mkdir: mkdir4 = mkdirSync4, task, thresholds, roleCostInputs } = {}) {
|
|
10299
11070
|
try {
|
|
10300
|
-
mkdir4(
|
|
10301
|
-
append(
|
|
11071
|
+
mkdir4(dirname6(path23), { recursive: true });
|
|
11072
|
+
append(path23, `${JSON.stringify(decision)}
|
|
10302
11073
|
`, "utf8");
|
|
10303
11074
|
if (isRouterDecision(decision)) {
|
|
10304
11075
|
try {
|
|
10305
11076
|
const records = buildShadowRecords({ decision, task, thresholds: thresholds || loadThresholds(), roleCostInputs });
|
|
10306
|
-
for (const record of records) append(
|
|
11077
|
+
for (const record of records) append(path23, `${JSON.stringify(record)}
|
|
10307
11078
|
`, "utf8");
|
|
10308
11079
|
} catch {
|
|
10309
11080
|
}
|
|
@@ -10321,7 +11092,7 @@ var init_auto_router = __esm({
|
|
|
10321
11092
|
init_effort_policy();
|
|
10322
11093
|
init_role_cost_shadow();
|
|
10323
11094
|
ROUTER_VERSION = "0.1.0";
|
|
10324
|
-
DECISION_FALLBACK_PATH =
|
|
11095
|
+
DECISION_FALLBACK_PATH = join9(homedir7(), ".claude", "vo-auto-router-decisions.jsonl");
|
|
10325
11096
|
MODES = /* @__PURE__ */ new Set(["off", "shadow", "on"]);
|
|
10326
11097
|
cachedThresholds = null;
|
|
10327
11098
|
isRouterDecision = (d) => Boolean(d && typeof d === "object" && typeof d.taskClass === "string" && typeof d.confidence === "number");
|
|
@@ -11294,9 +12065,9 @@ var init_inference_task_runner = __esm({
|
|
|
11294
12065
|
});
|
|
11295
12066
|
|
|
11296
12067
|
// ../../scripts/virtual-office/code-runner/isolation-audit.mjs
|
|
11297
|
-
import
|
|
12068
|
+
import fs12 from "node:fs";
|
|
11298
12069
|
import fsp11 from "node:fs/promises";
|
|
11299
|
-
import
|
|
12070
|
+
import path20 from "node:path";
|
|
11300
12071
|
async function defaultRun(command, args, cwd, options = {}) {
|
|
11301
12072
|
return runProcess2(command, args, { cwd, timeout: 6e4, ...options });
|
|
11302
12073
|
}
|
|
@@ -11309,7 +12080,7 @@ async function canonicalRootForWorktree(worktreeDir, run) {
|
|
|
11309
12080
|
"--path-format=absolute",
|
|
11310
12081
|
"--git-common-dir"
|
|
11311
12082
|
])).trim();
|
|
11312
|
-
const root =
|
|
12083
|
+
const root = path20.dirname(commonDir);
|
|
11313
12084
|
return samePath2(root, worktreeDir) ? null : root;
|
|
11314
12085
|
}
|
|
11315
12086
|
async function snapshot(root, run) {
|
|
@@ -11351,21 +12122,21 @@ async function changedPaths(root, run) {
|
|
|
11351
12122
|
}
|
|
11352
12123
|
async function quarantineCanonicalWrites({ baseline, worktreeDir, taskId, run, now }) {
|
|
11353
12124
|
const paths = await changedPaths(baseline.root, run);
|
|
11354
|
-
const quarantineDir =
|
|
11355
|
-
|
|
12125
|
+
const quarantineDir = path20.join(
|
|
12126
|
+
path20.dirname(worktreeDir),
|
|
11356
12127
|
".canonical-recovery",
|
|
11357
12128
|
`${String(taskId || "unknown").replace(/[^a-z0-9-]/gi, "-")}-${now().toISOString().replace(/[:.]/g, "-")}`
|
|
11358
12129
|
);
|
|
11359
12130
|
await fsp11.mkdir(quarantineDir, { recursive: true });
|
|
11360
12131
|
const patch = await git2(run, baseline.root, ["diff", "--binary", "HEAD"], { raw: true });
|
|
11361
|
-
await fsp11.writeFile(
|
|
12132
|
+
await fsp11.writeFile(path20.join(quarantineDir, "tracked.patch"), patch, "utf8");
|
|
11362
12133
|
for (const relative of paths.untracked) {
|
|
11363
|
-
const source =
|
|
11364
|
-
const target =
|
|
11365
|
-
await fsp11.mkdir(
|
|
12134
|
+
const source = path20.join(baseline.root, relative);
|
|
12135
|
+
const target = path20.join(quarantineDir, "untracked", relative);
|
|
12136
|
+
await fsp11.mkdir(path20.dirname(target), { recursive: true });
|
|
11366
12137
|
await fsp11.copyFile(source, target);
|
|
11367
12138
|
}
|
|
11368
|
-
await fsp11.writeFile(
|
|
12139
|
+
await fsp11.writeFile(path20.join(quarantineDir, "manifest.json"), `${JSON.stringify({
|
|
11369
12140
|
taskId,
|
|
11370
12141
|
canonicalRoot: baseline.root,
|
|
11371
12142
|
canonicalHead: baseline.head,
|
|
@@ -11387,9 +12158,9 @@ async function restoreExactCanonicalPaths(baseline, evidence, run) {
|
|
|
11387
12158
|
]);
|
|
11388
12159
|
}
|
|
11389
12160
|
for (const relative of evidence.untracked) {
|
|
11390
|
-
const target =
|
|
11391
|
-
const prefix = `${
|
|
11392
|
-
if (!target.startsWith(prefix) || !
|
|
12161
|
+
const target = path20.resolve(baseline.root, relative);
|
|
12162
|
+
const prefix = `${path20.resolve(baseline.root)}${path20.sep}`;
|
|
12163
|
+
if (!target.startsWith(prefix) || !fs12.existsSync(target)) continue;
|
|
11393
12164
|
await fsp11.rm(target, { force: true });
|
|
11394
12165
|
}
|
|
11395
12166
|
}
|
|
@@ -11425,7 +12196,7 @@ var init_isolation_audit = __esm({
|
|
|
11425
12196
|
init_process_runner2();
|
|
11426
12197
|
splitZ2 = (value) => String(value || "").split("\0").map((item) => item.trim()).filter(Boolean);
|
|
11427
12198
|
samePath2 = (left, right) => {
|
|
11428
|
-
const [a, b] = [left, right].map((value) =>
|
|
12199
|
+
const [a, b] = [left, right].map((value) => path20.resolve(value));
|
|
11429
12200
|
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
11430
12201
|
};
|
|
11431
12202
|
}
|
|
@@ -11785,7 +12556,7 @@ var init_publication_outcome = __esm({
|
|
|
11785
12556
|
|
|
11786
12557
|
// ../../scripts/virtual-office/code-runner/committed-scratch-cleanup.mjs
|
|
11787
12558
|
import fsp12 from "node:fs/promises";
|
|
11788
|
-
import
|
|
12559
|
+
import path21 from "node:path";
|
|
11789
12560
|
function defaultRun2(command, args, cwd, options = {}) {
|
|
11790
12561
|
return runProcess2(command, args, { cwd, ...options });
|
|
11791
12562
|
}
|
|
@@ -11793,13 +12564,13 @@ async function resolveSafeScratchTarget(worktreeDir, file) {
|
|
|
11793
12564
|
if (!isAgentScratch(file)) {
|
|
11794
12565
|
throw new Error(`refusing to remove non-scratch publication path: ${file}`);
|
|
11795
12566
|
}
|
|
11796
|
-
const root =
|
|
11797
|
-
const target =
|
|
11798
|
-
const relative =
|
|
11799
|
-
if (!relative || relative.startsWith(`..${
|
|
12567
|
+
const root = path21.resolve(worktreeDir);
|
|
12568
|
+
const target = path21.resolve(root, file);
|
|
12569
|
+
const relative = path21.relative(root, target);
|
|
12570
|
+
if (!relative || relative.startsWith(`..${path21.sep}`) || path21.isAbsolute(relative)) {
|
|
11800
12571
|
throw new Error(`refusing to remove publication scratch outside worktree: ${file}`);
|
|
11801
12572
|
}
|
|
11802
|
-
for (let cursor = target; cursor !== root; cursor =
|
|
12573
|
+
for (let cursor = target; cursor !== root; cursor = path21.dirname(cursor)) {
|
|
11803
12574
|
try {
|
|
11804
12575
|
if ((await fsp12.lstat(cursor)).isSymbolicLink()) {
|
|
11805
12576
|
throw new Error(`refusing to follow symlink while removing publication scratch: ${file}`);
|
|
@@ -11919,9 +12690,9 @@ var init_publication_scope = __esm({
|
|
|
11919
12690
|
});
|
|
11920
12691
|
|
|
11921
12692
|
// ../../scripts/virtual-office/code-runner/recovery-ledger.mjs
|
|
11922
|
-
import
|
|
12693
|
+
import fs13 from "node:fs";
|
|
11923
12694
|
import fsp13 from "node:fs/promises";
|
|
11924
|
-
import
|
|
12695
|
+
import path22 from "node:path";
|
|
11925
12696
|
function recoveryTaskId(prompt) {
|
|
11926
12697
|
const match = String(prompt || "").match(/VO_RECOVERY_FROM_CODE_TASK:\s*([0-9a-f-]{36})/i);
|
|
11927
12698
|
return match ? match[1].toLowerCase() : null;
|
|
@@ -11935,10 +12706,10 @@ function cloneLeaf(repo) {
|
|
|
11935
12706
|
function recoveryLedgerCandidates(repo, clonesRoot2) {
|
|
11936
12707
|
const leaf = cloneLeaf(repo);
|
|
11937
12708
|
if (!leaf || !clonesRoot2) return [];
|
|
11938
|
-
const canonical =
|
|
12709
|
+
const canonical = path22.join(clonesRoot2, leaf);
|
|
11939
12710
|
return [
|
|
11940
|
-
|
|
11941
|
-
|
|
12711
|
+
path22.join(clonesRoot2, ".agent-worktrees", leaf, "recovery-ledger.jsonl"),
|
|
12712
|
+
path22.join(canonical, ".agent-worktrees", "recovery-ledger.jsonl")
|
|
11942
12713
|
];
|
|
11943
12714
|
}
|
|
11944
12715
|
async function readLedger(file, readFile5) {
|
|
@@ -11957,7 +12728,7 @@ async function readLedger(file, readFile5) {
|
|
|
11957
12728
|
async function findPreservedRecovery(task, {
|
|
11958
12729
|
clonesRoot: clonesRoot2 = process.env.VO_CODE_RUNNER_CLONES_ROOT || "",
|
|
11959
12730
|
readFile: readFile5 = fsp13.readFile,
|
|
11960
|
-
exists =
|
|
12731
|
+
exists = fs13.existsSync
|
|
11961
12732
|
} = {}) {
|
|
11962
12733
|
const resumedFrom = /^[0-9a-f-]{36}$/iu.test(String(task.resumed_from || "")) ? String(task.resumed_from).toLowerCase() : null;
|
|
11963
12734
|
const originalTaskId = recoveryTaskId(task.prompt) ?? resumedFrom;
|
|
@@ -12272,7 +13043,7 @@ var init_cancellation_probe = __esm({
|
|
|
12272
13043
|
|
|
12273
13044
|
// ../../scripts/virtual-office/code-runner/detached-economics-spool.mjs
|
|
12274
13045
|
import { homedir as homedir8 } from "node:os";
|
|
12275
|
-
import { dirname as
|
|
13046
|
+
import { dirname as dirname7, join as join10 } from "node:path";
|
|
12276
13047
|
import { mkdir as mkdir3, readFile as readFile4, rename as rename2, writeFile as writeFile3 } from "node:fs/promises";
|
|
12277
13048
|
function withLock(operation) {
|
|
12278
13049
|
const result = serialized.then(operation, operation);
|
|
@@ -12290,7 +13061,7 @@ async function readEntries(file) {
|
|
|
12290
13061
|
}
|
|
12291
13062
|
}
|
|
12292
13063
|
async function writeEntries(file, entries) {
|
|
12293
|
-
await mkdir3(
|
|
13064
|
+
await mkdir3(dirname7(file), { recursive: true });
|
|
12294
13065
|
const temp = `${file}.${process.pid}.tmp`;
|
|
12295
13066
|
await writeFile3(temp, `${JSON.stringify(entries)}
|
|
12296
13067
|
`, "utf8");
|
|
@@ -12336,13 +13107,13 @@ var DEFAULT_FILE, serialized;
|
|
|
12336
13107
|
var init_detached_economics_spool = __esm({
|
|
12337
13108
|
"../../scripts/virtual-office/code-runner/detached-economics-spool.mjs"() {
|
|
12338
13109
|
"use strict";
|
|
12339
|
-
DEFAULT_FILE =
|
|
13110
|
+
DEFAULT_FILE = join10(homedir8(), ".vo", "detached-run-economics.json");
|
|
12340
13111
|
serialized = Promise.resolve();
|
|
12341
13112
|
}
|
|
12342
13113
|
});
|
|
12343
13114
|
|
|
12344
13115
|
// ../../scripts/virtual-office/code-runner/killed-run-outcome.mjs
|
|
12345
|
-
import { randomUUID as
|
|
13116
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
12346
13117
|
async function handleKilledRun({
|
|
12347
13118
|
client,
|
|
12348
13119
|
id,
|
|
@@ -12379,7 +13150,7 @@ async function handleKilledRun({
|
|
|
12379
13150
|
};
|
|
12380
13151
|
}
|
|
12381
13152
|
if (reason === "claim_authority_changed") {
|
|
12382
|
-
const occurrenceId =
|
|
13153
|
+
const occurrenceId = randomUUID6();
|
|
12383
13154
|
const economics = {
|
|
12384
13155
|
occurrence_id: occurrenceId,
|
|
12385
13156
|
runner_id: runnerId,
|
|
@@ -12479,13 +13250,13 @@ var init_runner_runtime_limits = __esm({
|
|
|
12479
13250
|
});
|
|
12480
13251
|
|
|
12481
13252
|
// ../../scripts/virtual-office/code-runner/daemon-config.mjs
|
|
12482
|
-
import
|
|
13253
|
+
import os5 from "node:os";
|
|
12483
13254
|
function loadCodeRunnerConfig(env2 = process.env, { log: log2 = () => {
|
|
12484
13255
|
} } = {}) {
|
|
12485
13256
|
const servedOperators = parseList(env2.VO_CODE_RUNNER_OPERATOR_IDS);
|
|
12486
13257
|
const allowAmbientGithub = env2.VO_CODE_RUNNER_ALLOW_AMBIENT_GH === "1";
|
|
12487
13258
|
return {
|
|
12488
|
-
runnerId: env2.VO_CODE_RUNNER_ID || `vo-code-runner-${
|
|
13259
|
+
runnerId: env2.VO_CODE_RUNNER_ID || `vo-code-runner-${os5.hostname()}`,
|
|
12489
13260
|
...resolveRunner(env2, { warn: (message) => log2(`agent-select: ${message}`) }),
|
|
12490
13261
|
permissionMode: env2.VO_CODE_RUNNER_PERMISSION_MODE || "acceptEdits",
|
|
12491
13262
|
maxConcurrency: Math.max(1, Number(env2.VO_CODE_TASK_MAX_CONCURRENCY || 2) || 2),
|
|
@@ -12495,7 +13266,7 @@ function loadCodeRunnerConfig(env2 = process.env, { log: log2 = () => {
|
|
|
12495
13266
|
requireGithubAppAuth: !allowAmbientGithub && servedOperators.length > 0,
|
|
12496
13267
|
allowAmbientGithub,
|
|
12497
13268
|
sessionForwardSec: Math.max(0, Number(env2.VO_SESSION_FORWARD_SEC ?? 30) || 0),
|
|
12498
|
-
operatorSeed: env2.VO_LOCAL_OPERATOR_SEED || env2.VO_CODE_RUNNER_ID || `local-${
|
|
13269
|
+
operatorSeed: env2.VO_LOCAL_OPERATOR_SEED || env2.VO_CODE_RUNNER_ID || `local-${os5.hostname()}`,
|
|
12499
13270
|
cancelPollMs: Math.max(1e3, Number(env2.VO_CODE_RUNNER_CANCEL_POLL_MS || 2500) || 2500),
|
|
12500
13271
|
maxWallClockMs: resolveMaxWallClockMs(env2.VO_CODE_RUNNER_MAX_WALL_CLOCK_MS),
|
|
12501
13272
|
watchEnabled: env2.VO_CODE_RUNNER_WATCH !== "0",
|
|
@@ -12674,10 +13445,10 @@ var init_task_worktree_preparation = __esm({
|
|
|
12674
13445
|
// ../../scripts/virtual-office/code-runner-daemon.mjs
|
|
12675
13446
|
var code_runner_daemon_exports = {};
|
|
12676
13447
|
__export(code_runner_daemon_exports, {
|
|
12677
|
-
main: () =>
|
|
13448
|
+
main: () => main2
|
|
12678
13449
|
});
|
|
12679
|
-
import { randomUUID as
|
|
12680
|
-
import { fileURLToPath as
|
|
13450
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
13451
|
+
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
12681
13452
|
function log(msg) {
|
|
12682
13453
|
console.log(`[code-runner ${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}`);
|
|
12683
13454
|
}
|
|
@@ -12819,16 +13590,12 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
|
|
|
12819
13590
|
return;
|
|
12820
13591
|
}
|
|
12821
13592
|
if (await taskWasCancelled({ client, id, run, safeProgress, log })) return;
|
|
13593
|
+
if (await gateTestGenTaskOrFail({ client, id, task, files, worktreeDir: wt.worktreeDir, log })) return;
|
|
13594
|
+
if (await enforceCompletionGateOrFail({ client, id, task, worktreeDir: wt.worktreeDir, log })) return;
|
|
12822
13595
|
const publicationTarget = await resolvePublicationTarget({ task, continuationRestore, worktreeDir: wt.worktreeDir, githubToken, allowAmbientGithubFallback: cfg.allowAmbientGithub });
|
|
12823
13596
|
const localBranch = await resolveOrCreateBranchAsync(wt.worktreeDir, "vo/code-task");
|
|
12824
13597
|
const publicationBranch = publicationTarget.targetBranch || localBranch;
|
|
12825
|
-
if (!await recordPublicationIntent({
|
|
12826
|
-
client,
|
|
12827
|
-
id,
|
|
12828
|
-
branch: publicationBranch,
|
|
12829
|
-
safeProgress,
|
|
12830
|
-
log
|
|
12831
|
-
})) {
|
|
13598
|
+
if (!await recordPublicationIntent({ client, id, branch: publicationBranch, safeProgress, log })) {
|
|
12832
13599
|
await reportCancelledRun({ client, id, run, safeProgress, log });
|
|
12833
13600
|
return;
|
|
12834
13601
|
}
|
|
@@ -12903,10 +13670,10 @@ Closes #${publicationTarget.supersedesPrNumber}` : "";
|
|
|
12903
13670
|
}
|
|
12904
13671
|
}
|
|
12905
13672
|
}
|
|
12906
|
-
async function
|
|
13673
|
+
async function main2({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
12907
13674
|
const cfg = loadCodeRunnerConfig(env2, { log });
|
|
12908
13675
|
await sweepStaleTaskAttachmentDirectories().catch((error) => log(`stale attachment cleanup failed: ${error.message}`));
|
|
12909
|
-
const runnerInstanceId =
|
|
13676
|
+
const runnerInstanceId = randomUUID7();
|
|
12910
13677
|
const client = createControlPlaneClient({
|
|
12911
13678
|
env: env2,
|
|
12912
13679
|
runnerId: cfg.runnerId,
|
|
@@ -13049,7 +13816,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
|
|
|
13049
13816
|
if (controlServer) controlServer.close();
|
|
13050
13817
|
log("stopped");
|
|
13051
13818
|
}
|
|
13052
|
-
var RATE_LIMIT_RESUME_ENABLED, sleep2, safeProgress,
|
|
13819
|
+
var RATE_LIMIT_RESUME_ENABLED, sleep2, safeProgress, invokedDirectly2;
|
|
13053
13820
|
var init_code_runner_daemon = __esm({
|
|
13054
13821
|
"../../scripts/virtual-office/code-runner-daemon.mjs"() {
|
|
13055
13822
|
"use strict";
|
|
@@ -13060,6 +13827,8 @@ var init_code_runner_daemon = __esm({
|
|
|
13060
13827
|
init_resolve_runner();
|
|
13061
13828
|
init_rate_limit_resume();
|
|
13062
13829
|
init_publish();
|
|
13830
|
+
init_test_gen_gate();
|
|
13831
|
+
init_completion_gate();
|
|
13063
13832
|
init_orphan_agent_reaper();
|
|
13064
13833
|
init_publish_async();
|
|
13065
13834
|
init_task_prompt();
|
|
@@ -13097,11 +13866,11 @@ var init_code_runner_daemon = __esm({
|
|
|
13097
13866
|
RATE_LIMIT_RESUME_ENABLED = process.env.VO_RATE_LIMIT_RESUME !== "0";
|
|
13098
13867
|
sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
13099
13868
|
safeProgress = makeSafeProgress(log);
|
|
13100
|
-
|
|
13869
|
+
invokedDirectly2 = process.argv[1] && fileURLToPath8(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).
|
|
13101
13870
|
import.meta.url.endsWith("code-runner-daemon.mjs");
|
|
13102
|
-
if (
|
|
13871
|
+
if (invokedDirectly2) {
|
|
13103
13872
|
const once2 = process.argv.includes("--once");
|
|
13104
|
-
|
|
13873
|
+
main2({ once: once2 }).catch((err) => {
|
|
13105
13874
|
console.error("[code-runner] fatal:", err);
|
|
13106
13875
|
process.exit(1);
|
|
13107
13876
|
});
|
|
@@ -13468,8 +14237,8 @@ var env = {
|
|
|
13468
14237
|
...pairedOperatorId ? { VO_CODE_RUNNER_OPERATOR_IDS: pairedOperatorId } : {}
|
|
13469
14238
|
};
|
|
13470
14239
|
var once = process.argv.includes("--once");
|
|
13471
|
-
var { main:
|
|
13472
|
-
|
|
14240
|
+
var { main: main3 } = await Promise.resolve().then(() => (init_code_runner_daemon(), code_runner_daemon_exports));
|
|
14241
|
+
main3({ env, once }).catch((err) => {
|
|
13473
14242
|
console.error("[vo-mcp runner] fatal:", err);
|
|
13474
14243
|
process.exit(1);
|
|
13475
14244
|
});
|