agent-hitch 0.1.0 → 0.2.0

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.
Files changed (92) hide show
  1. package/README.md +240 -126
  2. package/README.zh-CN.md +330 -0
  3. package/dist/bin/hitch.js +9 -0
  4. package/dist/bin/hitch.js.map +1 -0
  5. package/dist/scripts/check-release.js +25 -0
  6. package/dist/scripts/check-release.js.map +1 -0
  7. package/dist/scripts/check-syntax.js +32 -0
  8. package/dist/scripts/check-syntax.js.map +1 -0
  9. package/dist/src/adapters.js +461 -0
  10. package/dist/src/adapters.js.map +1 -0
  11. package/dist/src/artifacts.js +1081 -0
  12. package/dist/src/artifacts.js.map +1 -0
  13. package/dist/src/cli.js +699 -0
  14. package/dist/src/cli.js.map +1 -0
  15. package/dist/src/config.js +53 -0
  16. package/dist/src/config.js.map +1 -0
  17. package/dist/src/controller-runtime/hash.js +353 -0
  18. package/dist/src/controller-runtime/hash.js.map +1 -0
  19. package/dist/src/controller-runtime/store.js +323 -0
  20. package/dist/src/controller-runtime/store.js.map +1 -0
  21. package/dist/src/daemon.js +461 -0
  22. package/dist/src/daemon.js.map +1 -0
  23. package/dist/src/domain/types.js +10 -0
  24. package/dist/src/domain/types.js.map +1 -0
  25. package/dist/src/domain/validate.js +240 -0
  26. package/dist/src/domain/validate.js.map +1 -0
  27. package/dist/src/engine.js +465 -0
  28. package/dist/src/engine.js.map +1 -0
  29. package/dist/src/errors.js +14 -0
  30. package/dist/src/errors.js.map +1 -0
  31. package/dist/src/eval-tools.js +318 -0
  32. package/dist/src/eval-tools.js.map +1 -0
  33. package/dist/src/evals.js +313 -0
  34. package/dist/src/evals.js.map +1 -0
  35. package/dist/src/events.js +80 -0
  36. package/dist/src/events.js.map +1 -0
  37. package/dist/src/feedback/service.js +315 -0
  38. package/dist/src/feedback/service.js.map +1 -0
  39. package/dist/src/fs.js +45 -0
  40. package/dist/src/fs.js.map +1 -0
  41. package/dist/src/harbor-backend.js +280 -0
  42. package/dist/src/harbor-backend.js.map +1 -0
  43. package/dist/src/harness-reference.js +83 -0
  44. package/dist/src/harness-reference.js.map +1 -0
  45. package/dist/src/line-stream.js +20 -0
  46. package/dist/src/line-stream.js.map +1 -0
  47. package/dist/src/locks.js +38 -0
  48. package/dist/src/locks.js.map +1 -0
  49. package/dist/src/package-root.js +40 -0
  50. package/dist/src/package-root.js.map +1 -0
  51. package/dist/src/process.js +50 -0
  52. package/dist/src/process.js.map +1 -0
  53. package/dist/src/registry.js +81 -0
  54. package/dist/src/registry.js.map +1 -0
  55. package/dist/src/scheduler.js +162 -0
  56. package/dist/src/scheduler.js.map +1 -0
  57. package/dist/src/trajectories/contract.js +17 -0
  58. package/dist/src/trajectories/contract.js.map +1 -0
  59. package/dist/src/trajectories/format.js +127 -0
  60. package/dist/src/trajectories/format.js.map +1 -0
  61. package/dist/src/trajectories/projector.js +385 -0
  62. package/dist/src/trajectories/projector.js.map +1 -0
  63. package/dist/src/trajectories/store.js +281 -0
  64. package/dist/src/trajectories/store.js.map +1 -0
  65. package/dist/src/workspaces.js +858 -0
  66. package/dist/src/workspaces.js.map +1 -0
  67. package/docs/schemas/controller-runtime-manifest.schema.json +57 -0
  68. package/docs/schemas/controller-runtime-ref.schema.json +16 -0
  69. package/docs/schemas/message-feedback.schema.json +37 -0
  70. package/docs/schemas/trajectory-ref.schema.json +30 -0
  71. package/integrations/harbor/hitch_harbor_agent.py +176 -4
  72. package/package.json +19 -11
  73. package/bin/hitch.js +0 -9
  74. package/src/adapters.js +0 -361
  75. package/src/artifacts.js +0 -948
  76. package/src/cli.js +0 -505
  77. package/src/config.js +0 -51
  78. package/src/daemon.js +0 -416
  79. package/src/engine.js +0 -386
  80. package/src/errors.js +0 -12
  81. package/src/eval-tools.js +0 -331
  82. package/src/evals.js +0 -276
  83. package/src/events.js +0 -69
  84. package/src/fs.js +0 -43
  85. package/src/harbor-backend.js +0 -285
  86. package/src/harness-reference.js +0 -78
  87. package/src/line-stream.js +0 -17
  88. package/src/locks.js +0 -33
  89. package/src/process.js +0 -49
  90. package/src/registry.js +0 -84
  91. package/src/scheduler.js +0 -156
  92. package/src/workspaces.js +0 -893
@@ -0,0 +1,318 @@
1
+ import { constants } from "node:fs";
2
+ import { access, mkdir, rm } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { spawn } from "node:child_process";
5
+ import { SCHEMA_VERSION, statePaths } from "./config.js";
6
+ import { HitchError, invalidInput } from "./errors.js";
7
+ import { atomicWriteJSON, ensureDir, readJSON } from "./fs.js";
8
+ import { terminateProcess } from "./process.js";
9
+ import { detectVersion, resolveExecutable } from "./registry.js";
10
+ export const DEFAULT_HARBOR_VERSION = "0.21.0";
11
+ export const HARBOR_CREDENTIAL_ENV = [
12
+ "DEEPSEEK_API_KEY",
13
+ "DEEPSEEK_BASE_URL",
14
+ "OPENAI_API_KEY",
15
+ "OPENAI_BASE_URL",
16
+ "OPENAI_ORG_ID",
17
+ "OPENAI_ORGANIZATION",
18
+ "ANTHROPIC_API_KEY",
19
+ "ANTHROPIC_AUTH_TOKEN",
20
+ "ANTHROPIC_BASE_URL",
21
+ "CLAUDE_CODE_OAUTH_TOKEN",
22
+ "GOOGLE_API_KEY",
23
+ "GEMINI_API_KEY",
24
+ "AZURE_OPENAI_API_KEY",
25
+ "AZURE_OPENAI_ENDPOINT",
26
+ "AZURE_OPENAI_API_VERSION",
27
+ "AWS_ACCESS_KEY_ID",
28
+ "AWS_SECRET_ACCESS_KEY",
29
+ "AWS_SESSION_TOKEN",
30
+ "AWS_REGION",
31
+ "AWS_DEFAULT_REGION",
32
+ "GITHUB_TOKEN",
33
+ "GH_TOKEN",
34
+ ];
35
+ const PROVIDER_CREDENTIAL_ENV = [
36
+ "DEEPSEEK_API_KEY",
37
+ "OPENAI_API_KEY",
38
+ "ANTHROPIC_API_KEY",
39
+ "ANTHROPIC_AUTH_TOKEN",
40
+ "CLAUDE_CODE_OAUTH_TOKEN",
41
+ "GOOGLE_API_KEY",
42
+ "GEMINI_API_KEY",
43
+ "AZURE_OPENAI_API_KEY",
44
+ "AWS_ACCESS_KEY_ID",
45
+ ];
46
+ export async function setupHarbor({ root, version = DEFAULT_HARBOR_VERSION, python, force = false, env = process.env, onProgress = () => { }, }) {
47
+ if (!root)
48
+ throw invalidInput("a Hitch state root is required for Harbor setup");
49
+ if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
50
+ throw invalidInput("Harbor version must be an exact semantic version");
51
+ }
52
+ const pythonInfo = await findPython({ explicit: python, env });
53
+ if (!pythonInfo.executable) {
54
+ throw new HitchError("Python 3.12 or newer was not found; install it or pass --python <path>", {
55
+ code: "python_unavailable",
56
+ exitCode: 3,
57
+ });
58
+ }
59
+ if (!pythonInfo.supported) {
60
+ throw new HitchError(`Harbor requires Python 3.12 or newer; found ${pythonInfo.version || "an unknown version"}`, {
61
+ code: "python_unsupported",
62
+ exitCode: 3,
63
+ });
64
+ }
65
+ const toolsDirectory = statePaths(root).tools;
66
+ const installDirectory = path.join(toolsDirectory, `harbor-${version}`);
67
+ const harborExecutable = venvExecutable(installDirectory, "harbor");
68
+ const currentPath = path.join(toolsDirectory, "harbor.json");
69
+ const installedVersion = await installedHarborVersion(harborExecutable);
70
+ if (installedVersion === version && !force) {
71
+ const manifest = await writeHarborSelection(currentPath, {
72
+ version,
73
+ pythonInfo,
74
+ installDirectory,
75
+ harborExecutable,
76
+ cacheHit: true,
77
+ });
78
+ return manifest;
79
+ }
80
+ if (installedVersion && !force) {
81
+ throw new HitchError(`managed Harbor at ${installDirectory} reports ${installedVersion}; rerun with --force to replace it`, {
82
+ code: "harbor_setup_conflict",
83
+ exitCode: 3,
84
+ });
85
+ }
86
+ await ensureDir(toolsDirectory);
87
+ if (force)
88
+ await rm(installDirectory, { recursive: true, force: true });
89
+ try {
90
+ await mkdir(installDirectory);
91
+ }
92
+ catch (error) {
93
+ if (error?.code === "EEXIST") {
94
+ throw new HitchError(`incomplete Harbor installation already exists at ${installDirectory}; rerun with --force`, {
95
+ code: "harbor_setup_incomplete",
96
+ exitCode: 3,
97
+ });
98
+ }
99
+ throw error;
100
+ }
101
+ try {
102
+ onProgress(`Creating an isolated Python environment with ${pythonInfo.version}`);
103
+ await requireCommand(pythonInfo.executable, ["-m", "venv", installDirectory], {
104
+ env,
105
+ code: "harbor_setup_failed",
106
+ timeoutMs: 5 * 60_000,
107
+ });
108
+ const environmentPython = venvExecutable(installDirectory, "python");
109
+ onProgress(`Installing harbor==${version}`);
110
+ await requireCommand(environmentPython, [
111
+ "-m", "pip", "install", "--disable-pip-version-check", "--no-input", `harbor==${version}`,
112
+ ], {
113
+ env,
114
+ code: "harbor_setup_failed",
115
+ timeoutMs: 20 * 60_000,
116
+ });
117
+ const observedVersion = await installedHarborVersion(harborExecutable);
118
+ if (observedVersion !== version) {
119
+ throw new HitchError(`installed Harbor reported ${observedVersion || "no version"}; expected ${version}`, {
120
+ code: "harbor_setup_failed",
121
+ exitCode: 13,
122
+ });
123
+ }
124
+ return await writeHarborSelection(currentPath, {
125
+ version,
126
+ pythonInfo,
127
+ installDirectory,
128
+ harborExecutable,
129
+ cacheHit: false,
130
+ });
131
+ }
132
+ catch (error) {
133
+ await rm(installDirectory, { recursive: true, force: true });
134
+ throw error;
135
+ }
136
+ }
137
+ export async function doctorHarbor({ root, python, harbor, docker, env = process.env }) {
138
+ if (!root)
139
+ throw invalidInput("a Hitch state root is required for eval doctor");
140
+ const pythonInfo = await findPython({ explicit: python, env });
141
+ const harborInfo = await locateHarbor({ root, explicit: harbor, env });
142
+ const dockerConfigured = docker || env.HITCH_DOCKER_PATH || "docker";
143
+ const dockerExecutable = await resolveExecutable(dockerConfigured, env.PATH || "");
144
+ let dockerVersion = "";
145
+ let dockerDiagnostic = "";
146
+ if (dockerExecutable) {
147
+ const result = await captureCommand(dockerExecutable, ["version", "--format", "{{.Server.Version}}"], {
148
+ env,
149
+ timeoutMs: 10_000,
150
+ });
151
+ dockerVersion = result.code === 0 ? result.stdout.trim() : "";
152
+ dockerDiagnostic = result.code === 0 ? "" : (result.stderr.trim() || result.stdout.trim() || "Docker daemon is unavailable");
153
+ }
154
+ const credentials = PROVIDER_CREDENTIAL_ENV.filter((name) => typeof env[name] === "string" && env[name].trim());
155
+ const checks = {
156
+ python: pythonInfo.executable && pythonInfo.supported
157
+ ? { status: "ok", executable: pythonInfo.executable, version: pythonInfo.version, required: ">=3.12" }
158
+ : { status: "error", executable: pythonInfo.executable || null, version: pythonInfo.version || null, required: ">=3.12", message: "Python 3.12 or newer is required to install Harbor" },
159
+ harbor: harborInfo.executable
160
+ ? { status: "ok", executable: harborInfo.executable, version: harborInfo.version || null, source: harborInfo.source }
161
+ : { status: "error", executable: null, version: null, source: harborInfo.source, message: `Harbor executable not found: ${harborInfo.requested}` },
162
+ docker: dockerExecutable && dockerVersion
163
+ ? { status: "ok", executable: dockerExecutable, version: dockerVersion, daemon: "running" }
164
+ : { status: "error", executable: dockerExecutable || null, version: null, daemon: dockerExecutable ? "unavailable" : "not_checked", message: dockerExecutable ? dockerDiagnostic : `Docker executable not found: ${dockerConfigured}` },
165
+ credentials: credentials.length > 0
166
+ ? { status: "ok", present: credentials }
167
+ : { status: "warning", present: [], message: "No common provider credential is set; pass credentials before running a hosted-model eval" },
168
+ };
169
+ const ready = [checks.python, checks.harbor, checks.docker].every((check) => check?.status === "ok");
170
+ return {
171
+ schema_version: SCHEMA_VERSION,
172
+ backend: "harbor",
173
+ status: ready ? (checks.credentials?.status === "ok" ? "ready" : "ready_with_warnings") : "action_required",
174
+ ready,
175
+ checks,
176
+ };
177
+ }
178
+ export async function locateHarbor({ root, explicit, env = process.env } = {}) {
179
+ const configured = explicit || env.HITCH_HARBOR_PATH;
180
+ if (configured) {
181
+ const executable = await resolveExecutable(configured, env.PATH || "");
182
+ return {
183
+ executable,
184
+ version: executable ? await installedHarborVersion(executable) : "",
185
+ source: explicit ? "option" : "environment",
186
+ requested: configured,
187
+ };
188
+ }
189
+ const managed = root ? await managedHarborExecutable(root) : null;
190
+ if (managed) {
191
+ return {
192
+ executable: managed,
193
+ version: await installedHarborVersion(managed),
194
+ source: "managed",
195
+ requested: managed,
196
+ };
197
+ }
198
+ const executable = await resolveExecutable("harbor", env.PATH || "");
199
+ return {
200
+ executable,
201
+ version: executable ? await installedHarborVersion(executable) : "",
202
+ source: "path",
203
+ requested: "harbor",
204
+ };
205
+ }
206
+ export async function managedHarborExecutable(root) {
207
+ const toolsDirectory = statePaths(root).tools;
208
+ const current = await readJSON(path.join(toolsDirectory, "harbor.json"), null).catch(() => null);
209
+ if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(current?.version || ""))
210
+ return null;
211
+ const version = current?.version;
212
+ const executable = venvExecutable(path.join(toolsDirectory, `harbor-${version}`), "harbor");
213
+ try {
214
+ await access(executable, constants.X_OK);
215
+ return executable;
216
+ }
217
+ catch {
218
+ return null;
219
+ }
220
+ }
221
+ async function findPython({ explicit, env }) {
222
+ const requested = explicit || env.HITCH_PYTHON_PATH;
223
+ const candidates = requested ? [requested] : ["python3.13", "python3.12", "python3"];
224
+ let firstFound = null;
225
+ for (const candidate of candidates) {
226
+ const executable = await resolveExecutable(candidate, env.PATH || "");
227
+ if (!executable)
228
+ continue;
229
+ const result = await captureCommand(executable, ["-c", "import sys; print('.'.join(map(str, sys.version_info[:3])))"], {
230
+ env,
231
+ timeoutMs: 5_000,
232
+ });
233
+ const version = result.code === 0 ? result.stdout.trim().split(/\s+/)[0] || "" : "";
234
+ const supported = pythonVersionSupported(version);
235
+ const info = { executable, version, supported };
236
+ firstFound ||= info;
237
+ if (supported || requested)
238
+ return info;
239
+ }
240
+ return firstFound || { executable: null, version: "", supported: false };
241
+ }
242
+ function pythonVersionSupported(version) {
243
+ const match = String(version).match(/^(\d+)\.(\d+)(?:\.\d+)?$/);
244
+ if (!match)
245
+ return false;
246
+ const major = Number(match[1]);
247
+ const minor = Number(match[2]);
248
+ return major > 3 || (major === 3 && minor >= 12);
249
+ }
250
+ async function installedHarborVersion(executable) {
251
+ try {
252
+ await access(executable, constants.X_OK);
253
+ }
254
+ catch {
255
+ return "";
256
+ }
257
+ const value = await detectVersion(executable, ["--version"]);
258
+ return value.match(/\b\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?\b/)?.[0] || "";
259
+ }
260
+ async function writeHarborSelection(currentPath, { version, pythonInfo, installDirectory, harborExecutable, cacheHit, }) {
261
+ const manifest = {
262
+ schema_version: SCHEMA_VERSION,
263
+ tool: "harbor",
264
+ version,
265
+ executable: harborExecutable,
266
+ install_directory: installDirectory,
267
+ python: { executable: pythonInfo.executable || "", version: pythonInfo.version },
268
+ cache_hit: cacheHit,
269
+ selected_at: new Date().toISOString(),
270
+ };
271
+ await atomicWriteJSON(currentPath, manifest);
272
+ return manifest;
273
+ }
274
+ function venvExecutable(directory, name) {
275
+ return process.platform === "win32"
276
+ ? path.join(directory, "Scripts", `${name}.exe`)
277
+ : path.join(directory, "bin", name);
278
+ }
279
+ async function requireCommand(executable, args, { env, code, timeoutMs }) {
280
+ const result = await captureCommand(executable, args, { env, timeoutMs });
281
+ if (result.code === 0)
282
+ return result;
283
+ const detail = result.stderr.trim() || result.stdout.trim();
284
+ throw new HitchError(`${path.basename(executable)} exited with code ${result.code ?? "null"}${detail ? `: ${detail}` : ""}`, {
285
+ code,
286
+ exitCode: 13,
287
+ });
288
+ }
289
+ function captureCommand(executable, args, { env = process.env, timeoutMs = 10_000 } = {}) {
290
+ return new Promise((resolve, reject) => {
291
+ const child = spawn(executable, args, {
292
+ env,
293
+ stdio: ["ignore", "pipe", "pipe"],
294
+ detached: process.platform !== "win32",
295
+ windowsHide: true,
296
+ });
297
+ let stdout = "";
298
+ let stderr = "";
299
+ let timedOut = false;
300
+ const append = (current, chunk) => `${current}${chunk}`.slice(-1_000_000);
301
+ child.stdout.on("data", (chunk) => { stdout = append(stdout, chunk); });
302
+ child.stderr.on("data", (chunk) => { stderr = append(stderr, chunk); });
303
+ const timer = setTimeout(() => {
304
+ timedOut = true;
305
+ terminateProcess(child).catch(() => { });
306
+ }, timeoutMs);
307
+ timer.unref?.();
308
+ child.once("error", (error) => {
309
+ clearTimeout(timer);
310
+ reject(error);
311
+ });
312
+ child.once("close", (code, signal) => {
313
+ clearTimeout(timer);
314
+ resolve({ code, signal, stdout, stderr, timed_out: timedOut });
315
+ });
316
+ });
317
+ }
318
+ //# sourceMappingURL=eval-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval-tools.js","sourceRoot":"","sources":["../../src/eval-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,313 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { createWriteStream } from "node:fs";
3
+ import { readdir } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { resolveHarness } from "./artifacts.js";
6
+ import { SCHEMA_VERSION, statePaths } from "./config.js";
7
+ import { HitchError, invalidInput } from "./errors.js";
8
+ import { atomicWriteJSON, ensureDir, readJSON } from "./fs.js";
9
+ import { parseHarnessReference } from "./harness-reference.js";
10
+ import { lockedHarnessRef, runHarborBackend } from "./harbor-backend.js";
11
+ import { ensureControllerRuntime, writeRuntimeReference, inspectEvalRuntimeKind } from "./controller-runtime/store.js";
12
+ export const DEFAULT_EVAL_TIMEOUT_MS = 15 * 60 * 1_000;
13
+ export const DEFAULT_EVAL_SETUP_TIMEOUT_MS = 30 * 60 * 1_000;
14
+ const HARBOR_EVAL_BYPASS_ARG = {
15
+ codex: "--dangerously-bypass-approvals-and-sandbox",
16
+ opencode: "--dangerously-skip-permissions",
17
+ };
18
+ export function newEvalId() {
19
+ return `eval_${randomUUID().replaceAll("-", "")}`;
20
+ }
21
+ export async function validateEvalRequest(input) {
22
+ if (!input || typeof input !== "object" || Array.isArray(input))
23
+ throw invalidInput("eval request must be a JSON object");
24
+ const allowed = new Set([
25
+ "schema_version", "backend", "dataset", "harness_ref", "model", "attempts",
26
+ "max_concurrent", "timeout_ms", "setup_timeout_ms", "agent_args", "pass_env",
27
+ ]);
28
+ const unexpected = Object.keys(input).find((field) => !allowed.has(field));
29
+ if (unexpected)
30
+ throw invalidInput(`unknown eval request field: ${unexpected}`);
31
+ if (input.schema_version !== undefined && input.schema_version !== SCHEMA_VERSION)
32
+ throw invalidInput(`unsupported schema_version: ${input.schema_version}`);
33
+ if ((input.backend || "harbor") !== "harbor")
34
+ throw invalidInput("only the harbor eval backend is currently supported");
35
+ if (typeof input.dataset !== "string" || !input.dataset.trim())
36
+ throw invalidInput("dataset must be a non-empty string");
37
+ if (typeof input.harness_ref !== "string" || !input.harness_ref.trim())
38
+ throw invalidInput("harness_ref must be a non-empty string");
39
+ const reference = parseHarnessReference(input.harness_ref);
40
+ if (reference.selector.type === "installed") {
41
+ throw invalidInput("eval requires an immutable harness ref: version:<exact> or commit:<sha>");
42
+ }
43
+ if (reference.selector.type === "commit" && reference.selector.source?.explicit) {
44
+ throw invalidInput("eval does not yet support local git+file harness refs; use a registered remote commit");
45
+ }
46
+ const attempts = positiveInteger(input.attempts ?? 1, "attempts");
47
+ const maxConcurrent = positiveInteger(input.max_concurrent ?? 4, "max_concurrent");
48
+ const timeout = nonNegativeNumber(input.timeout_ms ?? DEFAULT_EVAL_TIMEOUT_MS, "timeout_ms");
49
+ const setupTimeout = nonNegativeNumber(input.setup_timeout_ms ?? DEFAULT_EVAL_SETUP_TIMEOUT_MS, "setup_timeout_ms");
50
+ if (input.model !== undefined && typeof input.model !== "string")
51
+ throw invalidInput("model must be a string");
52
+ if (input.agent_args !== undefined && (!Array.isArray(input.agent_args) || input.agent_args.some((value) => typeof value !== "string"))) {
53
+ throw invalidInput("agent_args must be an array of strings");
54
+ }
55
+ if (input.pass_env !== undefined && (!Array.isArray(input.pass_env) || input.pass_env.some((value) => typeof value !== "string"))) {
56
+ throw invalidInput("pass_env must be an array of strings");
57
+ }
58
+ const agentArgs = Array.isArray(input.agent_args) ? [...input.agent_args] : [];
59
+ const bypassArg = HARBOR_EVAL_BYPASS_ARG[reference.harness_id];
60
+ if (bypassArg && !agentArgs.includes(bypassArg))
61
+ agentArgs.unshift(bypassArg);
62
+ return {
63
+ schema_version: SCHEMA_VERSION,
64
+ backend: "harbor",
65
+ dataset: String(input.dataset).trim(),
66
+ harness_ref: reference.canonical,
67
+ model: typeof input.model === "string" ? input.model : "",
68
+ attempts,
69
+ max_concurrent: maxConcurrent,
70
+ timeout_ms: timeout,
71
+ setup_timeout_ms: setupTimeout,
72
+ agent_args: agentArgs,
73
+ pass_env: [...new Set(Array.isArray(input.pass_env) ? input.pass_env : [])],
74
+ };
75
+ }
76
+ export async function runEval({ evalId = newEvalId(), request, root, env = process.env, harborExecutable, signal, onEvent }) {
77
+ if (!root)
78
+ throw invalidInput("a Hitch state root is required for eval");
79
+ const normalized = await validateEvalRequest(request);
80
+ const evalDirectory = await ensureDir(path.join(statePaths(root).evals, evalId));
81
+ const startedAt = new Date();
82
+ const sink = new EvalEventSink(evalDirectory, evalId, onEvent);
83
+ await sink.open();
84
+ await atomicWriteJSON(path.join(evalDirectory, "request.json"), normalized);
85
+ let result;
86
+ try {
87
+ sink.emit({ type: "eval.started", backend: normalized.backend, dataset: normalized.dataset });
88
+ const resolvedRevision = await resolveHarness(normalized.harness_ref, { root, env });
89
+ if (resolvedRevision.source.type === "git" && resolvedRevision.source.registered !== true) {
90
+ throw invalidInput("eval requires a registered remote Git source");
91
+ }
92
+ // Phase 2: the shared, read-only, SHA-256-addressed controller runtime
93
+ // cache replaces the per-eval Hitch runtime copy (spec §4).
94
+ const controllerRuntime = await ensureControllerRuntime({ root });
95
+ const runtimeRefFile = await writeRuntimeReference(evalDirectory, controllerRuntime);
96
+ sink.emit({
97
+ type: "eval.controller-runtime",
98
+ runtime_id: controllerRuntime.runtime_id,
99
+ cache_hit: controllerRuntime.cache_hit,
100
+ reference: runtimeRefFile,
101
+ });
102
+ const plan = {
103
+ schema_version: SCHEMA_VERSION,
104
+ eval_id: evalId,
105
+ backend: "harbor",
106
+ candidate: {
107
+ id: "candidate-1",
108
+ requested_harness_ref: normalized.harness_ref,
109
+ harness_ref: lockedHarnessRef(resolvedRevision),
110
+ harness_id: resolvedRevision.harness_id,
111
+ revision_identity: resolvedRevision.identity,
112
+ model: normalized.model || null,
113
+ },
114
+ dataset: normalized.dataset,
115
+ attempts: normalized.attempts,
116
+ max_concurrent: normalized.max_concurrent,
117
+ controller_runtime: {
118
+ runtime_id: controllerRuntime.runtime_id,
119
+ manifest_digest: controllerRuntime.manifest_digest,
120
+ },
121
+ created_at: new Date().toISOString(),
122
+ };
123
+ await atomicWriteJSON(path.join(evalDirectory, "resolution.json"), resolvedRevision);
124
+ await atomicWriteJSON(path.join(evalDirectory, "plan.json"), plan);
125
+ sink.emit({
126
+ type: "eval.planned",
127
+ harness: resolvedRevision.harness_id,
128
+ revision_identity: resolvedRevision.identity,
129
+ attempts: normalized.attempts,
130
+ });
131
+ const backendRun = await runHarborBackend({
132
+ evalDirectory,
133
+ request: normalized,
134
+ root,
135
+ resolvedRevision,
136
+ runtimeDirectory: controllerRuntime.directory,
137
+ runtimeId: controllerRuntime.runtime_id,
138
+ env,
139
+ ...(harborExecutable !== undefined ? { harborExecutable } : {}),
140
+ ...(signal ? { signal } : {}),
141
+ emit: (event) => sink.emit(event),
142
+ });
143
+ const cancelled = signal?.aborted;
144
+ const succeeded = !cancelled && backendRun.backend.process_exit_code === 0 && backendRun.rawResult !== null;
145
+ result = {
146
+ schema_version: SCHEMA_VERSION,
147
+ eval_id: evalId,
148
+ status: cancelled ? "cancelled" : succeeded ? "succeeded" : "failed",
149
+ exit_code: cancelled ? 9 : succeeded ? 0 : 13,
150
+ backend: backendRun.backend,
151
+ candidate: plan.candidate,
152
+ dataset: normalized.dataset,
153
+ summary: backendRun.summary,
154
+ ...(succeeded ? {} : {
155
+ error: {
156
+ code: cancelled ? "cancelled" : "harbor_failed",
157
+ message: cancelled
158
+ ? "eval was cancelled"
159
+ : backendRun.rawResult === null
160
+ ? `Harbor exited without a result (code ${backendRun.backend.process_exit_code ?? "null"})`
161
+ : `Harbor exited with code ${backendRun.backend.process_exit_code ?? "null"}`,
162
+ },
163
+ }),
164
+ started_at: startedAt.toISOString(),
165
+ completed_at: new Date().toISOString(),
166
+ };
167
+ }
168
+ catch (error) {
169
+ const typed = error instanceof HitchError;
170
+ result = {
171
+ schema_version: SCHEMA_VERSION,
172
+ eval_id: evalId,
173
+ status: signal?.aborted ? "cancelled" : "failed",
174
+ exit_code: signal?.aborted ? 9 : typed ? error.exitCode : 12,
175
+ error: {
176
+ code: signal?.aborted ? "cancelled" : typed ? error.code : "internal_error",
177
+ message: error?.message || String(error),
178
+ },
179
+ started_at: startedAt.toISOString(),
180
+ completed_at: new Date().toISOString(),
181
+ };
182
+ }
183
+ await atomicWriteJSON(path.join(evalDirectory, "result.json"), result);
184
+ sink.emit({ type: result.status === "succeeded" ? "eval.completed" : "eval.failed", status: result.status, exit_code: result.exit_code, error: result.error });
185
+ await sink.close();
186
+ return result;
187
+ }
188
+ export async function listEvals({ root }) {
189
+ const directory = statePaths(root).evals;
190
+ let entries;
191
+ try {
192
+ entries = await readdir(directory, { withFileTypes: true });
193
+ }
194
+ catch (error) {
195
+ if (error?.code === "ENOENT")
196
+ return [];
197
+ throw error;
198
+ }
199
+ const evals = [];
200
+ for (const entry of entries) {
201
+ if (!entry.isDirectory() || !entry.name.startsWith("eval_"))
202
+ continue;
203
+ const result = await readJSON(path.join(directory, entry.name, "result.json"), null).catch(() => null);
204
+ const request = await readJSON(path.join(directory, entry.name, "request.json"), null).catch(() => null);
205
+ if (!result && !request)
206
+ continue;
207
+ evals.push({
208
+ eval_id: entry.name,
209
+ status: result?.status || "running",
210
+ backend: result?.backend?.name || request?.backend || null,
211
+ dataset: result?.dataset || request?.dataset || null,
212
+ harness_ref: result?.candidate?.harness_ref || request?.harness_ref || null,
213
+ primary_reward: result?.summary?.primary_reward ?? null,
214
+ started_at: result?.started_at || null,
215
+ completed_at: result?.completed_at || null,
216
+ });
217
+ }
218
+ return evals.sort((left, right) => String(right.started_at || right.eval_id).localeCompare(String(left.started_at || left.eval_id)));
219
+ }
220
+ export async function inspectEval(evalId, { root }) {
221
+ if (typeof evalId !== "string" || !/^eval_[a-f0-9]{32}$/.test(evalId))
222
+ throw invalidInput(`invalid eval ID: ${evalId}`);
223
+ const directory = path.join(statePaths(root).evals, evalId);
224
+ const request = await readJSON(path.join(directory, "request.json"), null);
225
+ if (!request)
226
+ throw new HitchError(`eval not found: ${evalId}`, { code: "eval_not_found", exitCode: 3 });
227
+ return {
228
+ schema_version: SCHEMA_VERSION,
229
+ eval_id: evalId,
230
+ directory,
231
+ request,
232
+ resolution: await readJSON(path.join(directory, "resolution.json"), null),
233
+ plan: await readJSON(path.join(directory, "plan.json"), null),
234
+ result: await readJSON(path.join(directory, "result.json"), null),
235
+ runtime_storage: await inspectEvalRuntimeKind(directory),
236
+ };
237
+ }
238
+ class EvalEventSink {
239
+ path;
240
+ evalId;
241
+ onEvent;
242
+ sequence = 0;
243
+ pending = Promise.resolve();
244
+ stream;
245
+ streamError;
246
+ constructor(evalDirectory, evalId, onEvent = () => { }) {
247
+ this.path = path.join(evalDirectory, "events.jsonl");
248
+ this.evalId = evalId;
249
+ this.onEvent = onEvent || (() => { });
250
+ }
251
+ async open() {
252
+ await ensureDir(path.dirname(this.path));
253
+ this.stream = createWriteStream(this.path, { flags: "a", mode: 0o600 });
254
+ this.stream.on("error", (error) => { this.streamError ||= error; });
255
+ }
256
+ emit(event) {
257
+ const framed = {
258
+ schema_version: SCHEMA_VERSION,
259
+ sequence: ++this.sequence,
260
+ timestamp: new Date().toISOString(),
261
+ eval_id: this.evalId,
262
+ ...event,
263
+ };
264
+ this.pending = this.pending.then(() => writeChunk(this.stream, `${JSON.stringify(framed)}\n`));
265
+ try {
266
+ this.onEvent(framed);
267
+ }
268
+ catch { /* Observers cannot break eval persistence. */ }
269
+ return framed;
270
+ }
271
+ async close() {
272
+ let failure;
273
+ try {
274
+ await this.pending;
275
+ }
276
+ catch (error) {
277
+ failure = error;
278
+ }
279
+ try {
280
+ await closeStream(this.stream);
281
+ }
282
+ catch (error) {
283
+ failure ||= error;
284
+ }
285
+ failure ||= this.streamError;
286
+ if (failure)
287
+ throw failure;
288
+ }
289
+ }
290
+ function writeChunk(stream, chunk) {
291
+ return new Promise((resolve, reject) => stream.write(chunk, (error) => error ? reject(error) : resolve()));
292
+ }
293
+ function closeStream(stream) {
294
+ if (!stream)
295
+ return Promise.resolve();
296
+ return new Promise((resolve, reject) => {
297
+ stream.once("error", reject);
298
+ stream.end(resolve);
299
+ });
300
+ }
301
+ function positiveInteger(value, name) {
302
+ const parsed = Number(value);
303
+ if (!Number.isInteger(parsed) || parsed <= 0)
304
+ throw invalidInput(`${name} must be a positive integer`);
305
+ return parsed;
306
+ }
307
+ function nonNegativeNumber(value, name) {
308
+ const parsed = Number(value);
309
+ if (!Number.isFinite(parsed) || parsed < 0)
310
+ throw invalidInput(`${name} must be a non-negative number`);
311
+ return parsed;
312
+ }
313
+ //# sourceMappingURL=evals.js.map