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,280 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createWriteStream } from "node:fs";
3
+ import { readdir, stat } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { HitchError, invalidInput } from "./errors.js";
6
+ import { atomicWriteJSON, ensureDir, readJSON } from "./fs.js";
7
+ import { consumeLines } from "./line-stream.js";
8
+ import { terminateProcess } from "./process.js";
9
+ import { detectVersion, fingerprintExecutable } from "./registry.js";
10
+ import { HARBOR_CREDENTIAL_ENV, locateHarbor } from "./eval-tools.js";
11
+ import { packageRoot } from "./package-root.js";
12
+ const BRIDGE_DIRECTORY = path.join(packageRoot(), "integrations", "harbor");
13
+ export async function runHarborBackend({ evalDirectory, request, root, resolvedRevision, runtimeDirectory, runtimeId, env = process.env, harborExecutable, signal, emit = () => { }, }) {
14
+ const backendDirectory = await ensureDir(path.join(evalDirectory, "harbor"));
15
+ const executable = await discoverHarbor(harborExecutable, root, env);
16
+ const version = await detectVersion(executable, ["--version"]);
17
+ const identity = await fingerprintExecutable(executable);
18
+ const jobName = "job";
19
+ const configPath = path.join(backendDirectory, "job.json");
20
+ const jobDirectory = path.join(backendDirectory, jobName);
21
+ const resultPath = path.join(jobDirectory, "result.json");
22
+ const config = await buildHarborJobConfig({
23
+ request,
24
+ resolvedRevision,
25
+ runtimeDirectory,
26
+ runtimeId,
27
+ backendDirectory,
28
+ jobName,
29
+ env,
30
+ });
31
+ await atomicWriteJSON(configPath, config);
32
+ emit({ type: "eval.backend.started", backend: "harbor", executable, version: version || null });
33
+ const invocation = await invokeHarbor(executable, ["run", "--config", configPath, "--yes"], {
34
+ cwd: evalDirectory,
35
+ env: withBridgePythonPath(env),
36
+ stdoutPath: path.join(backendDirectory, "stdout.log"),
37
+ stderrPath: path.join(backendDirectory, "stderr.log"),
38
+ ...(signal ? { signal } : {}),
39
+ emit,
40
+ });
41
+ const jobResult = await readJSON(resultPath, null);
42
+ const rawResult = jobResult ? await attachTrialResults(jobDirectory, jobResult) : null;
43
+ emit({
44
+ type: "eval.backend.completed",
45
+ backend: "harbor",
46
+ process_exit_code: invocation.code,
47
+ signal: invocation.signal,
48
+ result_available: rawResult !== null,
49
+ });
50
+ return {
51
+ backend: {
52
+ name: "harbor",
53
+ executable,
54
+ version: version || null,
55
+ identity,
56
+ config_path: configPath,
57
+ result_path: rawResult ? resultPath : null,
58
+ stdout_path: path.join(backendDirectory, "stdout.log"),
59
+ stderr_path: path.join(backendDirectory, "stderr.log"),
60
+ process_exit_code: invocation.code,
61
+ signal: invocation.signal,
62
+ },
63
+ rawResult,
64
+ summary: rawResult ? normalizeHarborResult(rawResult) : null,
65
+ };
66
+ }
67
+ async function attachTrialResults(jobDirectory, jobResult) {
68
+ if (Array.isArray(jobResult.trial_results))
69
+ return jobResult;
70
+ let entries;
71
+ try {
72
+ entries = await readdir(jobDirectory, { withFileTypes: true });
73
+ }
74
+ catch (error) {
75
+ if (error?.code === "ENOENT")
76
+ return jobResult;
77
+ throw error;
78
+ }
79
+ const trialResults = [];
80
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
81
+ if (!entry.isDirectory())
82
+ continue;
83
+ const trial = await readJSON(path.join(jobDirectory, entry.name, "result.json"), null);
84
+ if (trial?.trial_name && trial?.task_name)
85
+ trialResults.push(trial);
86
+ }
87
+ return { ...jobResult, trial_results: trialResults };
88
+ }
89
+ export async function buildHarborJobConfig({ request, resolvedRevision, runtimeDirectory, runtimeId, backendDirectory, jobName = "job", env = process.env, }) {
90
+ const timeoutSeconds = request.timeout_ms > 0 ? Math.ceil(request.timeout_ms / 1_000) : null;
91
+ const setupTimeoutSeconds = request.setup_timeout_ms > 0 ? Math.ceil(request.setup_timeout_ms / 1_000) : null;
92
+ const agent = {
93
+ import_path: "hitch_harbor_agent:HitchHarborAgent",
94
+ model_name: request.model || null,
95
+ kwargs: {
96
+ candidate_id: "candidate-1",
97
+ harness_ref: lockedHarnessRef(resolvedRevision),
98
+ revision_identity: resolvedRevision.identity,
99
+ // The bridge consumes the shared compiled runtime cache. The local
100
+ // absolute cache path is diagnostic machine-local state, not identity
101
+ // (spec §4.2); `runtime_id` records the exact execution payload.
102
+ hitch_runtime_dir: runtimeDirectory,
103
+ ...(runtimeId ? { controller_runtime_id: runtimeId } : {}),
104
+ hitch_timeout_ms: request.timeout_ms,
105
+ agent_args: request.agent_args,
106
+ workdir: "/app",
107
+ },
108
+ env: credentialEnvironment(request.pass_env, env),
109
+ include_logs: ["hitch-*"],
110
+ };
111
+ if (timeoutSeconds !== null)
112
+ agent.override_timeout_sec = timeoutSeconds + 30;
113
+ if (setupTimeoutSeconds !== null)
114
+ agent.override_setup_timeout_sec = setupTimeoutSeconds;
115
+ return compact({
116
+ job_name: jobName,
117
+ jobs_dir: backendDirectory,
118
+ n_attempts: request.attempts,
119
+ n_concurrent_trials: request.max_concurrent,
120
+ environment: { type: "docker", delete: true },
121
+ agents: [agent],
122
+ datasets: [await datasetConfig(request.dataset)],
123
+ tasks: [],
124
+ });
125
+ }
126
+ export function lockedHarnessRef(resolvedRevision) {
127
+ if (resolvedRevision?.revision?.type === "version" && resolvedRevision.revision.version) {
128
+ return `${resolvedRevision.harness_id}@version:${resolvedRevision.revision.version}`;
129
+ }
130
+ if (resolvedRevision?.revision?.type === "commit" && resolvedRevision.revision.commit) {
131
+ return `${resolvedRevision.harness_id}@commit:${resolvedRevision.revision.commit}`;
132
+ }
133
+ throw invalidInput("Harbor eval requires a resolved exact version or commit");
134
+ }
135
+ export function normalizeHarborResult(raw) {
136
+ const trials = Array.isArray(raw?.trial_results) ? raw.trial_results : [];
137
+ const rewardValues = new Map();
138
+ const normalizedTrials = trials.map((trial) => {
139
+ const verifier = (trial?.verifier_result || {});
140
+ const rewards = (verifier.rewards || {});
141
+ for (const [name, value] of Object.entries(rewards)) {
142
+ if (typeof value !== "number" || !Number.isFinite(value))
143
+ continue;
144
+ const values = rewardValues.get(name) || [];
145
+ values.push(value);
146
+ rewardValues.set(name, values);
147
+ }
148
+ return {
149
+ task_name: trial?.task_name || null,
150
+ trial_name: trial?.trial_name || null,
151
+ status: trial?.exception_info ? "errored" : "completed",
152
+ rewards,
153
+ exception: trial?.exception_info || null,
154
+ };
155
+ });
156
+ const rewards = Object.fromEntries([...rewardValues.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([name, values]) => [name, {
157
+ count: values.length,
158
+ mean: values.reduce((sum, value) => sum + value, 0) / values.length,
159
+ min: Math.min(...values),
160
+ max: Math.max(...values),
161
+ }]));
162
+ const rewardEntries = Object.entries(rewards);
163
+ const primary = rewards.reward || rewardEntries[0]?.[1] || null;
164
+ const stats = (raw?.stats || {});
165
+ return {
166
+ n_trials: raw?.n_total_trials ?? trials.length,
167
+ n_completed: stats.n_completed_trials ?? normalizedTrials.filter((trial) => trial.status === "completed").length,
168
+ n_errored: stats.n_errored_trials ?? normalizedTrials.filter((trial) => trial.status === "errored").length,
169
+ n_cancelled: stats.n_cancelled_trials ?? 0,
170
+ primary_reward: primary?.mean ?? null,
171
+ rewards,
172
+ trials: normalizedTrials,
173
+ };
174
+ }
175
+ async function discoverHarbor(explicit, root, env) {
176
+ const located = await locateHarbor({ root, explicit, env });
177
+ if (!located.executable) {
178
+ throw new HitchError(`Harbor executable not found: ${located.requested}`, {
179
+ code: "harbor_unavailable",
180
+ exitCode: 3,
181
+ });
182
+ }
183
+ return located.executable;
184
+ }
185
+ async function datasetConfig(value) {
186
+ if (typeof value !== "string" || !value.trim())
187
+ throw invalidInput("dataset must be a non-empty string");
188
+ const raw = value.trim();
189
+ const localPath = path.resolve(raw);
190
+ try {
191
+ if ((await stat(localPath)).isDirectory())
192
+ return { path: localPath };
193
+ }
194
+ catch (error) {
195
+ if (error?.code !== "ENOENT")
196
+ throw error;
197
+ }
198
+ const separator = raw.lastIndexOf("@");
199
+ const name = separator > 0 ? raw.slice(0, separator) : raw;
200
+ const version = separator > 0 ? raw.slice(separator + 1) : "";
201
+ if (!name)
202
+ throw invalidInput(`invalid Harbor dataset: ${value}`);
203
+ return name.includes("/")
204
+ ? { name, ref: version || "latest" }
205
+ : compact({ name, version: version || undefined });
206
+ }
207
+ function credentialEnvironment(explicitNames, env) {
208
+ const names = new Set(HARBOR_CREDENTIAL_ENV.filter((name) => env[name] !== undefined));
209
+ for (const name of explicitNames || []) {
210
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
211
+ throw invalidInput(`invalid environment variable name: ${name}`);
212
+ if (env[name] === undefined)
213
+ throw invalidInput(`environment variable is not set: ${name}`);
214
+ names.add(name);
215
+ }
216
+ return Object.fromEntries([...names].sort().map((name) => [name, `\${${name}}`]));
217
+ }
218
+ function withBridgePythonPath(env) {
219
+ return {
220
+ ...env,
221
+ PYTHONPATH: [BRIDGE_DIRECTORY, env.PYTHONPATH].filter(Boolean).join(path.delimiter),
222
+ };
223
+ }
224
+ function invokeHarbor(executable, args, { cwd, env, stdoutPath, stderrPath, signal, emit }) {
225
+ return new Promise((resolve, reject) => {
226
+ const stdout = createWriteStream(stdoutPath, { flags: "w", mode: 0o600 });
227
+ const stderr = createWriteStream(stderrPath, { flags: "w", mode: 0o600 });
228
+ const child = spawn(executable, args, {
229
+ cwd,
230
+ env,
231
+ stdio: ["ignore", "pipe", "pipe"],
232
+ detached: process.platform !== "win32",
233
+ windowsHide: true,
234
+ });
235
+ child.stdout.pipe(stdout);
236
+ child.stderr.pipe(stderr);
237
+ consumeLines(child.stdout, (line) => emit({ type: "eval.backend.output", stream: "stdout", text: line }));
238
+ consumeLines(child.stderr, (line) => emit({ type: "eval.backend.output", stream: "stderr", text: line }));
239
+ let settled = false;
240
+ const abort = () => terminateProcess(child).catch(() => { });
241
+ signal?.addEventListener("abort", abort, { once: true });
242
+ child.once("error", (error) => {
243
+ if (settled)
244
+ return;
245
+ settled = true;
246
+ signal?.removeEventListener("abort", abort);
247
+ stdout.destroy();
248
+ stderr.destroy();
249
+ reject(new HitchError(`failed to launch Harbor: ${error.message}`, {
250
+ code: "harbor_launch_failed",
251
+ exitCode: 6,
252
+ cause: error,
253
+ }));
254
+ });
255
+ child.once("close", (code, processSignal) => {
256
+ if (settled)
257
+ return;
258
+ settled = true;
259
+ signal?.removeEventListener("abort", abort);
260
+ Promise.all([closeWriteStream(stdout), closeWriteStream(stderr)])
261
+ .then(() => resolve({ code, signal: processSignal }))
262
+ .catch(reject);
263
+ });
264
+ if (signal?.aborted)
265
+ abort();
266
+ });
267
+ }
268
+ function closeWriteStream(stream) {
269
+ return new Promise((resolve, reject) => {
270
+ if (stream.closed)
271
+ return resolve();
272
+ stream.once("error", reject);
273
+ stream.once("close", resolve);
274
+ stream.end();
275
+ });
276
+ }
277
+ function compact(value) {
278
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined && entry !== null));
279
+ }
280
+ //# sourceMappingURL=harbor-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harbor-backend.js","sourceRoot":"","sources":["../../src/harbor-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { fileURLToPath, pathToFileURL } from "node:url";
2
+ import path from "node:path";
3
+ import { invalidInput } from "./errors.js";
4
+ const VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
5
+ const COMMIT_PATTERN = /^[0-9a-fA-F]{7,64}$/;
6
+ const HARNESS_ID_PATTERN = /^[a-z][a-z0-9-]*$/;
7
+ export function parseHarnessReference(value) {
8
+ if (typeof value !== "string" || !value.trim())
9
+ throw invalidInput("harness reference must be a non-empty string");
10
+ const raw = value.trim();
11
+ const separator = raw.indexOf("@");
12
+ const harnessId = separator < 0 ? raw : raw.slice(0, separator);
13
+ const revision = separator < 0 ? "installed" : raw.slice(separator + 1);
14
+ if (!HARNESS_ID_PATTERN.test(harnessId))
15
+ throw invalidInput(`invalid harness name: ${harnessId || raw}`);
16
+ if (!revision)
17
+ throw invalidInput(`harness reference is missing a selector: ${raw}`);
18
+ if (revision === "installed") {
19
+ return canonicalReference(raw, harnessId, { type: "installed" });
20
+ }
21
+ if (revision.startsWith("version:")) {
22
+ const version = revision.slice("version:".length);
23
+ if (!VERSION_PATTERN.test(version)) {
24
+ throw invalidInput(`version selector must be an exact semantic version: ${version || "(empty)"}`);
25
+ }
26
+ return canonicalReference(raw, harnessId, { type: "version", value: version });
27
+ }
28
+ if (revision.startsWith("commit:")) {
29
+ const commit = revision.slice("commit:".length);
30
+ assertCommit(commit);
31
+ return canonicalReference(raw, harnessId, { type: "commit", value: commit.toLowerCase() });
32
+ }
33
+ if (revision.startsWith("git+")) {
34
+ const hash = revision.lastIndexOf("#");
35
+ if (hash < 0)
36
+ throw invalidInput("explicit Git references require #<commit>");
37
+ const sourceValue = revision.slice("git+".length, hash);
38
+ const commit = revision.slice(hash + 1);
39
+ assertCommit(commit);
40
+ let source;
41
+ try {
42
+ source = new URL(sourceValue);
43
+ }
44
+ catch (error) {
45
+ throw invalidInput(`invalid Git source URL: ${sourceValue}`, { cause: error });
46
+ }
47
+ if (source.protocol !== "file:") {
48
+ throw invalidInput("explicit Git sources are limited to file:// URLs; use the registered source for remote commits");
49
+ }
50
+ const localPath = path.resolve(fileURLToPath(source));
51
+ const sourceUrl = pathToFileURL(localPath).href;
52
+ return canonicalReference(raw, harnessId, {
53
+ type: "commit",
54
+ value: commit.toLowerCase(),
55
+ source: { type: "git", url: sourceUrl, local_path: localPath, explicit: true },
56
+ });
57
+ }
58
+ throw invalidInput(`unsupported harness selector in ${raw}; use installed, version:<exact>, or commit:<sha>`);
59
+ }
60
+ function canonicalReference(raw, harnessId, selector) {
61
+ let suffix;
62
+ if (selector.type === "installed") {
63
+ suffix = "installed";
64
+ }
65
+ else if (selector.type === "commit" && selector.source) {
66
+ suffix = `git+${selector.source.url}#${selector.value}`;
67
+ }
68
+ else {
69
+ suffix = `${selector.type}:${selector.value}`;
70
+ }
71
+ return {
72
+ raw,
73
+ canonical: `${harnessId}@${suffix}`,
74
+ harness_id: harnessId,
75
+ selector,
76
+ };
77
+ }
78
+ function assertCommit(value) {
79
+ if (!COMMIT_PATTERN.test(value || "")) {
80
+ throw invalidInput(`commit selector must be a 7-64 character hexadecimal ID: ${value || "(empty)"}`);
81
+ }
82
+ }
83
+ //# sourceMappingURL=harness-reference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-reference.js","sourceRoot":"","sources":["../../src/harness-reference.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export function consumeLines(stream, onLine) {
2
+ let buffer = "";
3
+ stream.setEncoding("utf8");
4
+ stream.on("data", (chunk) => {
5
+ buffer += chunk;
6
+ for (;;) {
7
+ const newline = buffer.indexOf("\n");
8
+ if (newline < 0)
9
+ break;
10
+ const line = buffer.slice(0, newline).replace(/\r$/, "");
11
+ buffer = buffer.slice(newline + 1);
12
+ onLine(line);
13
+ }
14
+ });
15
+ stream.on("end", () => {
16
+ if (buffer.length > 0)
17
+ onLine(buffer.replace(/\r$/, ""));
18
+ });
19
+ }
20
+ //# sourceMappingURL=line-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-stream.js","sourceRoot":"","sources":["../../src/line-stream.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAAC,MAAgB,EAAE,MAA8B;IAC3E,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE;QAC3C,MAAM,IAAI,KAAK,CAAC;QAChB,SAAS,CAAC;YACR,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,OAAO,GAAG,CAAC;gBAAE,MAAM;YACvB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACzD,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;QACpB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { open, readFile, rm } from "node:fs/promises";
3
+ // Serializes stale-lock reclamation so an observation about an old owner can
4
+ // never be used to remove a lock that a new owner has just acquired.
5
+ export async function reclaimStaleLock(file, isStale) {
6
+ const guard = `${file}.reclaim`;
7
+ const owner = randomBytes(12).toString("hex");
8
+ let handle;
9
+ try {
10
+ handle = await open(guard, "wx", 0o600);
11
+ }
12
+ catch (error) {
13
+ if (error?.code === "EEXIST")
14
+ return false;
15
+ throw error;
16
+ }
17
+ try {
18
+ await handle.writeFile(`${JSON.stringify({ owner, pid: process.pid, created_at: new Date().toISOString() })}\n`);
19
+ await handle.sync();
20
+ if (!await isStale(file))
21
+ return false;
22
+ await rm(file, { force: true });
23
+ return true;
24
+ }
25
+ finally {
26
+ await handle.close().catch(() => { });
27
+ let current;
28
+ try {
29
+ current = JSON.parse(await readFile(guard, "utf8"));
30
+ }
31
+ catch {
32
+ current = null;
33
+ }
34
+ if (current?.owner === owner)
35
+ await rm(guard, { force: true });
36
+ }
37
+ }
38
+ //# sourceMappingURL=locks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locks.js","sourceRoot":"","sources":["../../src/locks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAEtD,6EAA6E;AAC7E,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,OAA2C;IAC9F,MAAM,KAAK,GAAG,GAAG,IAAI,UAAU,CAAC;IAChC,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QACtE,MAAM,KAAK,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACjH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,IAAI,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACvC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrC,IAAI,OAAmC,CAAC;QACxC,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAwB,CAAC;QAC7E,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,IAAI,OAAO,EAAE,KAAK,KAAK,KAAK;YAAE,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,CAAC;AACH,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Resolve the Hitch package root and version from the module location,
3
+ * tolerating both the source layout (`src/cli.ts`) and the compiled layout
4
+ * (`dist/src/cli.js`). Walks up until a `package.json` with a `name` is found.
5
+ */
6
+ import { readFileSync } from "node:fs";
7
+ import { dirname, join } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ let cachedRoot;
10
+ let cachedVersion;
11
+ export function packageRoot() {
12
+ if (cachedRoot)
13
+ return cachedRoot;
14
+ let directory = dirname(fileURLToPath(import.meta.url));
15
+ for (;;) {
16
+ const candidate = join(directory, "package.json");
17
+ try {
18
+ const metadata = JSON.parse(readFileSync(candidate, "utf8"));
19
+ if (metadata.name === "agent-hitch") {
20
+ cachedRoot = directory;
21
+ return directory;
22
+ }
23
+ }
24
+ catch {
25
+ // Keep walking up.
26
+ }
27
+ const parent = dirname(directory);
28
+ if (parent === directory)
29
+ throw new Error("could not locate the Hitch package root");
30
+ directory = parent;
31
+ }
32
+ }
33
+ export function packageVersion() {
34
+ if (cachedVersion)
35
+ return cachedVersion;
36
+ const metadata = JSON.parse(readFileSync(join(packageRoot(), "package.json"), "utf8"));
37
+ cachedVersion = metadata.version;
38
+ return cachedVersion;
39
+ }
40
+ //# sourceMappingURL=package-root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-root.js","sourceRoot":"","sources":["../../src/package-root.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,UAA8B,CAAC;AACnC,IAAI,aAAiC,CAAC;AAEtC,MAAM,UAAU,WAAW;IACzB,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,IAAI,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAuB,CAAC;YACnF,IAAI,QAAQ,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBACpC,UAAU,GAAG,SAAS,CAAC;gBACvB,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACrF,SAAS,GAAG,MAAM,CAAC;IACrB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAwB,CAAC;IAC9G,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,OAAO,aAAa,CAAC;AACvB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { spawn } from "node:child_process";
2
+ export async function terminateProcess(child, graceMs = 3_000) {
3
+ if (!child || child.exitCode !== null || child.signalCode !== null)
4
+ return;
5
+ if (process.platform === "win32") {
6
+ const killer = spawn("taskkill", ["/pid", String(child.pid), "/t", "/f"], {
7
+ stdio: "ignore",
8
+ windowsHide: true,
9
+ });
10
+ await waitForExitOrTimeout(killer, graceMs);
11
+ return;
12
+ }
13
+ try {
14
+ process.kill(-child.pid, "SIGTERM");
15
+ }
16
+ catch (error) {
17
+ if (error?.code !== "ESRCH")
18
+ throw error;
19
+ return;
20
+ }
21
+ await waitForExitOrTimeout(child, graceMs);
22
+ if (child.exitCode === null && child.signalCode === null) {
23
+ try {
24
+ process.kill(-child.pid, "SIGKILL");
25
+ }
26
+ catch (error) {
27
+ if (error?.code !== "ESRCH")
28
+ throw error;
29
+ }
30
+ }
31
+ }
32
+ export function delay(milliseconds) {
33
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
34
+ }
35
+ function waitForExitOrTimeout(child, milliseconds) {
36
+ return new Promise((resolve) => {
37
+ let settled = false;
38
+ const finish = () => {
39
+ if (settled)
40
+ return;
41
+ settled = true;
42
+ clearTimeout(timer);
43
+ child.removeListener("exit", finish);
44
+ resolve();
45
+ };
46
+ const timer = setTimeout(finish, milliseconds);
47
+ child.once("exit", finish);
48
+ });
49
+ }
50
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAsC,EAAE,OAAO,GAAG,KAAK;IAC5F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI;QAAE,OAAO;IAE3E,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;YACxE,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QACH,MAAM,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAE,KAAK,CAAC,GAAc,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,EAAE,IAAI,KAAK,OAAO;YAAE,MAAM,KAAK,CAAC;QACpE,OAAO;IACT,CAAC;IAED,MAAM,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QACzD,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,CAAE,KAAK,CAAC,GAAc,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,EAAE,IAAI,KAAK,OAAO;gBAAE,MAAM,KAAK,CAAC;QACtE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,YAAoB;IACxC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAmB,EAAE,YAAoB;IACrE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACrC,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { constants, createReadStream } from "node:fs";
2
+ import { access, lstat, realpath } from "node:fs/promises";
3
+ import { delimiter, isAbsolute, join, resolve } from "node:path";
4
+ import { spawn } from "node:child_process";
5
+ import { createHash } from "node:crypto";
6
+ import { getAdapter, listDefinitions, publicDefinition } from "./adapters.js";
7
+ export async function discoverAgents({ env = process.env, probeVersions = true, } = {}) {
8
+ return Promise.all(listDefinitions().map((definition) => inspectDefinition(definition, { env, probeVersions })));
9
+ }
10
+ export async function inspectAgent(id, { env = process.env, probeVersions = true } = {}) {
11
+ const definition = publicDefinition(getAdapter(id));
12
+ return inspectDefinition(definition, { env, probeVersions });
13
+ }
14
+ async function inspectDefinition(definition, { env, probeVersions }) {
15
+ const configured = env[definition.path_env]?.trim() || definition.command;
16
+ const executable = await resolveExecutable(configured, env.PATH || "");
17
+ if (!executable)
18
+ return { ...definition, status: "unavailable" };
19
+ const version = probeVersions
20
+ ? await detectVersion(executable, getAdapter(definition.id).version_args)
21
+ : "";
22
+ const identity = await fingerprintExecutable(executable);
23
+ return { ...definition, status: "available", executable, version, identity };
24
+ }
25
+ export async function resolveExecutable(command, searchPath) {
26
+ const candidates = isAbsolute(command) || command.includes("/") || command.includes("\\")
27
+ ? [resolve(command)]
28
+ : searchPath.split(delimiter).filter(Boolean).map((directory) => join(directory, command));
29
+ for (const candidate of candidates) {
30
+ try {
31
+ await access(candidate, constants.X_OK);
32
+ const info = await lstat(candidate);
33
+ if (info.isDirectory())
34
+ continue;
35
+ return await realpath(candidate);
36
+ }
37
+ catch {
38
+ // Keep probing PATH entries.
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ export async function detectVersion(executable, args, timeoutMs = 5_000) {
44
+ return new Promise((resolveVersion) => {
45
+ const child = spawn(executable, args, { stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
46
+ let stdout = "";
47
+ let stderr = "";
48
+ const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
49
+ child.stdout.on("data", (chunk) => { stdout += chunk; });
50
+ child.stderr.on("data", (chunk) => { stderr += chunk; });
51
+ child.once("error", () => {
52
+ clearTimeout(timer);
53
+ resolveVersion("");
54
+ });
55
+ child.once("close", () => {
56
+ clearTimeout(timer);
57
+ resolveVersion(selectVersionLine(stdout, stderr));
58
+ });
59
+ });
60
+ }
61
+ export async function fingerprintExecutable(executable) {
62
+ const hash = createHash("sha256");
63
+ for await (const chunk of createReadStream(executable))
64
+ hash.update(chunk);
65
+ const digest = hash.digest("hex");
66
+ return `sha256:${digest}`;
67
+ }
68
+ export function selectVersionLine(stdout, stderr) {
69
+ const streams = [stdout, stderr];
70
+ const versionPattern = /(?:^|\s)v?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?(?:\s|$)/;
71
+ for (const stream of streams) {
72
+ const match = String(stream || "")
73
+ .split(/\r?\n/)
74
+ .map((line) => line.trim())
75
+ .find((line) => versionPattern.test(line));
76
+ if (match)
77
+ return match;
78
+ }
79
+ return "";
80
+ }
81
+ //# sourceMappingURL=registry.js.map