agent-hitch 0.1.1 → 0.2.1

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 (263) hide show
  1. package/README.md +235 -132
  2. package/README.zh-CN.md +335 -0
  3. package/dist/bin/hitch.js +9 -0
  4. package/dist/bin/hitch.js.map +1 -0
  5. package/dist/scripts/check-architecture.js +159 -0
  6. package/dist/scripts/check-architecture.js.map +1 -0
  7. package/dist/scripts/check-release.js +25 -0
  8. package/dist/scripts/check-release.js.map +1 -0
  9. package/dist/scripts/check-syntax.js +32 -0
  10. package/dist/scripts/check-syntax.js.map +1 -0
  11. package/dist/src/adapters/catalog.js +55 -0
  12. package/dist/src/adapters/catalog.js.map +1 -0
  13. package/dist/src/adapters/contract.js +2 -0
  14. package/dist/src/adapters/contract.js.map +1 -0
  15. package/dist/src/adapters/discovery.js +22 -0
  16. package/dist/src/adapters/discovery.js.map +1 -0
  17. package/dist/src/adapters/index.js +3 -0
  18. package/dist/src/adapters/index.js.map +1 -0
  19. package/dist/src/adapters/providers/claude.js +69 -0
  20. package/dist/src/adapters/providers/claude.js.map +1 -0
  21. package/dist/src/adapters/providers/codex.js +74 -0
  22. package/dist/src/adapters/providers/codex.js.map +1 -0
  23. package/dist/src/adapters/providers/deepseek.js +51 -0
  24. package/dist/src/adapters/providers/deepseek.js.map +1 -0
  25. package/dist/src/adapters/providers/opencode.js +73 -0
  26. package/dist/src/adapters/providers/opencode.js.map +1 -0
  27. package/dist/src/adapters/providers/pi.js +82 -0
  28. package/dist/src/adapters/providers/pi.js.map +1 -0
  29. package/dist/src/adapters/providers/shared.js +82 -0
  30. package/dist/src/adapters/providers/shared.js.map +1 -0
  31. package/dist/src/artifacts/index.js +3 -0
  32. package/dist/src/artifacts/index.js.map +1 -0
  33. package/dist/src/artifacts/integrity.js +188 -0
  34. package/dist/src/artifacts/integrity.js.map +1 -0
  35. package/dist/src/artifacts/preparer.js +379 -0
  36. package/dist/src/artifacts/preparer.js.map +1 -0
  37. package/dist/src/artifacts/store.js +87 -0
  38. package/dist/src/artifacts/store.js.map +1 -0
  39. package/dist/src/artifacts/types.js +2 -0
  40. package/dist/src/artifacts/types.js.map +1 -0
  41. package/dist/src/backends/contract.js +2 -0
  42. package/dist/src/backends/contract.js.map +1 -0
  43. package/dist/src/backends/harbor/backend.js +305 -0
  44. package/dist/src/backends/harbor/backend.js.map +1 -0
  45. package/dist/src/backends/harbor/index.js +4 -0
  46. package/dist/src/backends/harbor/index.js.map +1 -0
  47. package/dist/src/backends/harbor/local-git-transport.js +447 -0
  48. package/dist/src/backends/harbor/local-git-transport.js.map +1 -0
  49. package/dist/src/backends/harbor/tools.js +314 -0
  50. package/dist/src/backends/harbor/tools.js.map +1 -0
  51. package/dist/src/backends/index.js +4 -0
  52. package/dist/src/backends/index.js.map +1 -0
  53. package/dist/src/cli/arguments.js +123 -0
  54. package/dist/src/cli/arguments.js.map +1 -0
  55. package/dist/src/cli/commands/compare.js +55 -0
  56. package/dist/src/cli/commands/compare.js.map +1 -0
  57. package/dist/src/cli/commands/daemon.js +106 -0
  58. package/dist/src/cli/commands/daemon.js.map +1 -0
  59. package/dist/src/cli/commands/eval.js +126 -0
  60. package/dist/src/cli/commands/eval.js.map +1 -0
  61. package/dist/src/cli/commands/feedback.js +84 -0
  62. package/dist/src/cli/commands/feedback.js.map +1 -0
  63. package/dist/src/cli/commands/inspect.js +20 -0
  64. package/dist/src/cli/commands/inspect.js.map +1 -0
  65. package/dist/src/cli/commands/list.js +17 -0
  66. package/dist/src/cli/commands/list.js.map +1 -0
  67. package/dist/src/cli/commands/prepare.js +21 -0
  68. package/dist/src/cli/commands/prepare.js.map +1 -0
  69. package/dist/src/cli/commands/resolve.js +17 -0
  70. package/dist/src/cli/commands/resolve.js.map +1 -0
  71. package/dist/src/cli/commands/run.js +83 -0
  72. package/dist/src/cli/commands/run.js.map +1 -0
  73. package/dist/src/cli/commands/runs.js +45 -0
  74. package/dist/src/cli/commands/runs.js.map +1 -0
  75. package/dist/src/cli/commands/trajectory.js +31 -0
  76. package/dist/src/cli/commands/trajectory.js.map +1 -0
  77. package/dist/src/cli/commands/workspace.js +44 -0
  78. package/dist/src/cli/commands/workspace.js.map +1 -0
  79. package/dist/src/cli/index.js +2 -0
  80. package/dist/src/cli/index.js.map +1 -0
  81. package/dist/src/cli/main.js +48 -0
  82. package/dist/src/cli/main.js.map +1 -0
  83. package/dist/src/cli/output.js +96 -0
  84. package/dist/src/cli/output.js.map +1 -0
  85. package/dist/src/controller-runtime/hash.js +353 -0
  86. package/dist/src/controller-runtime/hash.js.map +1 -0
  87. package/dist/src/controller-runtime/index.js +3 -0
  88. package/dist/src/controller-runtime/index.js.map +1 -0
  89. package/dist/src/controller-runtime/store.js +318 -0
  90. package/dist/src/controller-runtime/store.js.map +1 -0
  91. package/dist/src/daemon/auth.js +108 -0
  92. package/dist/src/daemon/auth.js.map +1 -0
  93. package/dist/src/daemon/client.js +76 -0
  94. package/dist/src/daemon/client.js.map +1 -0
  95. package/dist/src/daemon/index.js +5 -0
  96. package/dist/src/daemon/index.js.map +1 -0
  97. package/dist/src/daemon/launcher.js +24 -0
  98. package/dist/src/daemon/launcher.js.map +1 -0
  99. package/dist/src/daemon/scheduler.js +161 -0
  100. package/dist/src/daemon/scheduler.js.map +1 -0
  101. package/dist/src/daemon/server.js +316 -0
  102. package/dist/src/daemon/server.js.map +1 -0
  103. package/dist/src/domain/artifacts.js +2 -0
  104. package/dist/src/domain/artifacts.js.map +1 -0
  105. package/dist/src/domain/controller-runtime.js +2 -0
  106. package/dist/src/domain/controller-runtime.js.map +1 -0
  107. package/dist/src/domain/eval-records.js +2 -0
  108. package/dist/src/domain/eval-records.js.map +1 -0
  109. package/dist/src/domain/evals.js +2 -0
  110. package/dist/src/domain/evals.js.map +1 -0
  111. package/dist/src/domain/feedback.js +2 -0
  112. package/dist/src/domain/feedback.js.map +1 -0
  113. package/dist/src/domain/ids.js +10 -0
  114. package/dist/src/domain/ids.js.map +1 -0
  115. package/dist/src/domain/index.js +11 -0
  116. package/dist/src/domain/index.js.map +1 -0
  117. package/dist/src/domain/revisions.js +2 -0
  118. package/dist/src/domain/revisions.js.map +1 -0
  119. package/dist/src/domain/runs.js +3 -0
  120. package/dist/src/domain/runs.js.map +1 -0
  121. package/dist/src/domain/trajectories.js +2 -0
  122. package/dist/src/domain/trajectories.js.map +1 -0
  123. package/dist/src/domain/validation.js +429 -0
  124. package/dist/src/domain/validation.js.map +1 -0
  125. package/dist/src/domain/workspaces.js +2 -0
  126. package/dist/src/domain/workspaces.js.map +1 -0
  127. package/dist/src/evals/events.js +67 -0
  128. package/dist/src/evals/events.js.map +1 -0
  129. package/dist/src/evals/index.js +5 -0
  130. package/dist/src/evals/index.js.map +1 -0
  131. package/dist/src/evals/records.js +55 -0
  132. package/dist/src/evals/records.js.map +1 -0
  133. package/dist/src/evals/request.js +109 -0
  134. package/dist/src/evals/request.js.map +1 -0
  135. package/dist/src/evals/service.js +227 -0
  136. package/dist/src/evals/service.js.map +1 -0
  137. package/dist/src/evals/trial-import.js +394 -0
  138. package/dist/src/evals/trial-import.js.map +1 -0
  139. package/dist/src/feedback/index.js +2 -0
  140. package/dist/src/feedback/index.js.map +1 -0
  141. package/dist/src/feedback/service.js +314 -0
  142. package/dist/src/feedback/service.js.map +1 -0
  143. package/dist/src/foundation/config.js +54 -0
  144. package/dist/src/foundation/config.js.map +1 -0
  145. package/dist/src/foundation/errors.js +14 -0
  146. package/dist/src/foundation/errors.js.map +1 -0
  147. package/dist/src/foundation/executable.js +135 -0
  148. package/dist/src/foundation/executable.js.map +1 -0
  149. package/dist/src/foundation/fs.js +45 -0
  150. package/dist/src/foundation/fs.js.map +1 -0
  151. package/dist/src/foundation/hash.js +24 -0
  152. package/dist/src/foundation/hash.js.map +1 -0
  153. package/dist/src/foundation/index.js +11 -0
  154. package/dist/src/foundation/index.js.map +1 -0
  155. package/dist/src/foundation/line-stream.js +20 -0
  156. package/dist/src/foundation/line-stream.js.map +1 -0
  157. package/dist/src/foundation/locks.js +114 -0
  158. package/dist/src/foundation/locks.js.map +1 -0
  159. package/dist/src/foundation/package-root.js +41 -0
  160. package/dist/src/foundation/package-root.js.map +1 -0
  161. package/dist/src/foundation/process.js +50 -0
  162. package/dist/src/foundation/process.js.map +1 -0
  163. package/dist/src/revisions/index.js +4 -0
  164. package/dist/src/revisions/index.js.map +1 -0
  165. package/dist/src/revisions/reference.js +97 -0
  166. package/dist/src/revisions/reference.js.map +1 -0
  167. package/dist/src/revisions/resolver.js +25 -0
  168. package/dist/src/revisions/resolver.js.map +1 -0
  169. package/dist/src/revisions/sources/git.js +180 -0
  170. package/dist/src/revisions/sources/git.js.map +1 -0
  171. package/dist/src/revisions/sources/installed.js +45 -0
  172. package/dist/src/revisions/sources/installed.js.map +1 -0
  173. package/dist/src/revisions/sources/npm.js +97 -0
  174. package/dist/src/revisions/sources/npm.js.map +1 -0
  175. package/dist/src/runs/compare.js +132 -0
  176. package/dist/src/runs/compare.js.map +1 -0
  177. package/dist/src/runs/events.js +79 -0
  178. package/dist/src/runs/events.js.map +1 -0
  179. package/dist/src/runs/executor.js +480 -0
  180. package/dist/src/runs/executor.js.map +1 -0
  181. package/dist/src/runs/finalizer.js +22 -0
  182. package/dist/src/runs/finalizer.js.map +1 -0
  183. package/dist/src/runs/identity.js +35 -0
  184. package/dist/src/runs/identity.js.map +1 -0
  185. package/dist/src/runs/index.js +11 -0
  186. package/dist/src/runs/index.js.map +1 -0
  187. package/dist/src/runs/manifest.js +70 -0
  188. package/dist/src/runs/manifest.js.map +1 -0
  189. package/dist/src/runs/outcome.js +49 -0
  190. package/dist/src/runs/outcome.js.map +1 -0
  191. package/dist/src/runs/query.js +104 -0
  192. package/dist/src/runs/query.js.map +1 -0
  193. package/dist/src/runs/queued.js +54 -0
  194. package/dist/src/runs/queued.js.map +1 -0
  195. package/dist/src/runs/records.js +288 -0
  196. package/dist/src/runs/records.js.map +1 -0
  197. package/dist/src/runs/request.js +169 -0
  198. package/dist/src/runs/request.js.map +1 -0
  199. package/dist/src/trajectories/contract.js +17 -0
  200. package/dist/src/trajectories/contract.js.map +1 -0
  201. package/dist/src/trajectories/format.js +127 -0
  202. package/dist/src/trajectories/format.js.map +1 -0
  203. package/dist/src/trajectories/index.js +7 -0
  204. package/dist/src/trajectories/index.js.map +1 -0
  205. package/dist/src/trajectories/projector.js +385 -0
  206. package/dist/src/trajectories/projector.js.map +1 -0
  207. package/dist/src/trajectories/provider-capture.js +133 -0
  208. package/dist/src/trajectories/provider-capture.js.map +1 -0
  209. package/dist/src/trajectories/providers/deepseek.js +179 -0
  210. package/dist/src/trajectories/providers/deepseek.js.map +1 -0
  211. package/dist/src/trajectories/store.js +421 -0
  212. package/dist/src/trajectories/store.js.map +1 -0
  213. package/dist/src/workspaces/copy.js +142 -0
  214. package/dist/src/workspaces/copy.js.map +1 -0
  215. package/dist/src/workspaces/digest.js +47 -0
  216. package/dist/src/workspaces/digest.js.map +1 -0
  217. package/dist/src/workspaces/git.js +164 -0
  218. package/dist/src/workspaces/git.js.map +1 -0
  219. package/dist/src/workspaces/index.js +6 -0
  220. package/dist/src/workspaces/index.js.map +1 -0
  221. package/dist/src/workspaces/lifecycle.js +313 -0
  222. package/dist/src/workspaces/lifecycle.js.map +1 -0
  223. package/dist/src/workspaces/planner.js +80 -0
  224. package/dist/src/workspaces/planner.js.map +1 -0
  225. package/dist/src/workspaces/store.js +25 -0
  226. package/dist/src/workspaces/store.js.map +1 -0
  227. package/dist/src/workspaces/types.js +4 -0
  228. package/dist/src/workspaces/types.js.map +1 -0
  229. package/dist/src/workspaces/utils.js +56 -0
  230. package/dist/src/workspaces/utils.js.map +1 -0
  231. package/docs/schemas/controller-runtime-manifest.schema.json +57 -0
  232. package/docs/schemas/controller-runtime-ref.schema.json +16 -0
  233. package/docs/schemas/eval-request.schema.json +2 -0
  234. package/docs/schemas/eval-result.schema.json +36 -1
  235. package/docs/schemas/local-git-transport-manifest.schema.json +34 -0
  236. package/docs/schemas/message-feedback.schema.json +37 -0
  237. package/docs/schemas/result.schema.json +9 -0
  238. package/docs/schemas/run-context.schema.json +39 -0
  239. package/docs/schemas/run-manifest.schema.json +81 -0
  240. package/docs/schemas/run-request.schema.json +16 -1
  241. package/docs/schemas/trajectory-ref.schema.json +73 -0
  242. package/integrations/harbor/hitch_harbor_agent.py +551 -5
  243. package/package.json +37 -11
  244. package/bin/hitch.js +0 -9
  245. package/src/adapters.js +0 -435
  246. package/src/artifacts.js +0 -949
  247. package/src/cli.js +0 -505
  248. package/src/config.js +0 -51
  249. package/src/daemon.js +0 -416
  250. package/src/engine.js +0 -400
  251. package/src/errors.js +0 -12
  252. package/src/eval-tools.js +0 -334
  253. package/src/evals.js +0 -276
  254. package/src/events.js +0 -69
  255. package/src/fs.js +0 -43
  256. package/src/harbor-backend.js +0 -285
  257. package/src/harness-reference.js +0 -78
  258. package/src/line-stream.js +0 -17
  259. package/src/locks.js +0 -33
  260. package/src/process.js +0 -49
  261. package/src/registry.js +0 -84
  262. package/src/scheduler.js +0 -156
  263. package/src/workspaces.js +0 -893
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Controller runtime store: staging, promotion, cache lookup, and verified
3
+ * use of shared read-only controller runtime bundles (spec §4).
4
+ *
5
+ * New eval directories do not contain a complete Hitch runtime; they hold a
6
+ * durable `runtime.ref.json` reference. The shared bundle lives under
7
+ * `<hitch-root>/store/controller-runtimes/sha256/<64-hex>/`.
8
+ */
9
+ import { randomBytes } from "node:crypto";
10
+ import { createHash } from "node:crypto";
11
+ import { cp, mkdir, readFile, readdir, rename, rm, stat, chmod, open } from "node:fs/promises";
12
+ import path from "node:path";
13
+ import { HitchError, SCHEMA_VERSION, atomicWriteJSON, delay, ensureDir, packageRoot, readJSON, reclaimStaleLock, removeIfExists, statePaths } from "../foundation/index.js";
14
+ import { ControllerRuntimeIntegrityError, RUNTIME_PAYLOAD_RULES, canonicalEncodeManifest, hashRuntimePayload, verifyRuntimePayload, } from "./hash.js";
15
+ import { validateControllerRuntimeManifest } from "../domain/index.js";
16
+ /** The Hitch package root whose compiled payload is packaged as a controller runtime. */
17
+ export const PACKAGE_ROOT = packageRoot();
18
+ /**
19
+ * Ensure the shared controller runtime bundle for the current Hitch payload
20
+ * exists and is verified; returns its cache path and identity.
21
+ */
22
+ export async function ensureControllerRuntime({ root, payloadRoot = PACKAGE_ROOT, rules = RUNTIME_PAYLOAD_RULES }) {
23
+ if (!root)
24
+ throw new HitchError("a Hitch state root is required for the controller runtime", { code: "invalid_input", exitCode: 2 });
25
+ const paths = statePaths(root);
26
+ // Stage inside the state root's tmp/ directory so promotion is a same-
27
+ // filesystem atomic rename (spec §4.2 `tmp/runtime-staging-*`, §4.5).
28
+ const stagingBase = path.join(paths.temporary, "controller-runtime");
29
+ // Stage a fresh copy, hash it, and promote under a runtime-id lock.
30
+ const staging = await stagePayload(payloadRoot, rules, stagingBase);
31
+ try {
32
+ return await withRuntimeLock(paths, staging.runtimeId, async () => {
33
+ return promoteStagedRuntime(paths, staging);
34
+ });
35
+ }
36
+ finally {
37
+ await rm(staging.directory, { recursive: true, force: true }).catch(() => { });
38
+ }
39
+ }
40
+ async function stagePayload(payloadRoot, rules, stagingBase) {
41
+ const payloadRootReal = path.resolve(payloadRoot);
42
+ const hashResult = await hashRuntimePayload({ payloadRoot: payloadRootReal, rules });
43
+ const runtimeId = hashResult.runtimeId.replace("sha256:", "");
44
+ await ensureDir(stagingBase);
45
+ const staging = path.join(stagingBase, `runtime-staging-${runtimeId.slice(0, 12)}-${randomBytes(6).toString("hex")}`);
46
+ await mkdir(staging, { recursive: true });
47
+ // Copy the allowlisted payload into staging. Never hardlink from the
48
+ // development or installed package tree (spec §4.5).
49
+ const payloadDestination = path.join(staging, "payload");
50
+ await mkdir(payloadDestination, { recursive: true });
51
+ await copyPayload(payloadRootReal, payloadDestination, rules);
52
+ // Hash the staged payload and write its manifest; the complete tree is
53
+ // verified a second time during promotion.
54
+ const stagedHash = await hashRuntimePayload({ payloadRoot: payloadDestination, rules });
55
+ if (stagedHash.runtimeId !== hashResult.runtimeId) {
56
+ throw new ControllerRuntimeIntegrityError("staged runtime payload hash changed during staging");
57
+ }
58
+ await atomicWriteJSON(path.join(staging, "manifest.json"), stagedHash.manifest);
59
+ return { directory: staging, runtimeId };
60
+ }
61
+ async function copyPayload(sourceRoot, destinationRoot, rules) {
62
+ for (const rule of rules) {
63
+ const relative = rule.path || rule.directory || "";
64
+ const source = path.join(sourceRoot, ...relative.split("/"));
65
+ const destination = path.join(destinationRoot, ...relative.split("/"));
66
+ await ensureDir(path.dirname(destination));
67
+ await cp(source, destination, { recursive: true, force: false, errorOnExist: true });
68
+ }
69
+ }
70
+ async function promoteStagedRuntime(paths, staging) {
71
+ await ensureDir(paths.controllerRuntimes);
72
+ const destination = path.join(paths.controllerRuntimes, staging.runtimeId);
73
+ // If a valid bundle already exists, discard staging and return the cache hit
74
+ // (spec §4.5). Check first so a same-filesystem rename is never attempted
75
+ // onto an existing directory (POSIX rejects it).
76
+ if (await pathExists(destination)) {
77
+ try {
78
+ return await useControllerRuntimeById(paths, staging.runtimeId);
79
+ }
80
+ catch (error) {
81
+ if (error?.code !== "controller_runtime_integrity_mismatch")
82
+ throw error;
83
+ // The destination is corrupt: quarantine it before promoting the fresh
84
+ // staged bundle with the same runtime id (spec §4.5). The replacement
85
+ // carries the exact same bytes, so the id is never relabeled.
86
+ await quarantineInvalidRuntime(paths, destination, staging.runtimeId);
87
+ }
88
+ }
89
+ let promoted = false;
90
+ try {
91
+ await rename(staging.directory, destination);
92
+ promoted = true;
93
+ }
94
+ catch (error) {
95
+ if (error?.code !== "ENOTEMPTY" && error?.code !== "EEXIST")
96
+ throw error;
97
+ // A concurrent first use promoted first; validate the existing bundle.
98
+ }
99
+ if (promoted) {
100
+ const manifest = await loadManifest(destination);
101
+ await applyReadOnlyPermissions(destination, manifest.entrypoints.cli.path);
102
+ // Verify the promoted tree a second time before it can be used.
103
+ await verifyRuntimePayload(path.join(destination, "payload"), manifest);
104
+ return {
105
+ runtime_id: `sha256:${staging.runtimeId}`,
106
+ directory: destination,
107
+ manifest,
108
+ cache_hit: false,
109
+ manifest_digest: manifestDigest(manifest),
110
+ };
111
+ }
112
+ return useControllerRuntimeById(paths, staging.runtimeId);
113
+ }
114
+ async function quarantineInvalidRuntime(paths, destination, runtimeId) {
115
+ const quarantine = path.join(paths.temporary, `invalid-runtime-${runtimeId}-${randomBytes(6).toString("hex")}`);
116
+ await ensureDir(path.dirname(quarantine));
117
+ await rm(quarantine, { recursive: true, force: true }).catch(() => { });
118
+ try {
119
+ // The promoted bundle tree is read-only (0555/0444); make the root
120
+ // writable so the rename into quarantine is permitted on all platforms.
121
+ await chmod(destination, 0o755).catch(() => { });
122
+ await rename(destination, quarantine);
123
+ }
124
+ catch (error) {
125
+ if (error?.code === "ENOENT")
126
+ return;
127
+ throw error;
128
+ }
129
+ // Do not remove the quarantine eagerly; keep the corrupt bytes for
130
+ // diagnostics. A future GC command may reclaim it.
131
+ }
132
+ async function pathExists(file) {
133
+ try {
134
+ await stat(file);
135
+ return true;
136
+ }
137
+ catch (error) {
138
+ if (error?.code === "ENOENT")
139
+ return false;
140
+ throw error;
141
+ }
142
+ }
143
+ async function applyReadOnlyPermissions(directory, cliEntrypoint) {
144
+ if (process.platform === "win32")
145
+ return;
146
+ const stack = [directory];
147
+ while (stack.length > 0) {
148
+ const current = stack.pop();
149
+ const entries = await readdir(current, { withFileTypes: true });
150
+ for (const entry of entries) {
151
+ const absolute = path.join(current, entry.name);
152
+ if (entry.isDirectory()) {
153
+ stack.push(absolute);
154
+ }
155
+ else if (entry.isFile()) {
156
+ const payloadRelative = relativeToPayload(directory, absolute);
157
+ // Only the declared CLI entrypoint becomes executable (0555); sibling
158
+ // files such as .map sources stay read-only (0444) (spec §4.5).
159
+ const isEntrypoint = payloadRelative === cliEntrypoint;
160
+ await chmod(absolute, isEntrypoint ? 0o555 : 0o444);
161
+ }
162
+ }
163
+ await chmod(current, 0o555);
164
+ }
165
+ }
166
+ function relativeToPayload(directory, absolute) {
167
+ return path.relative(path.join(directory, "payload"), absolute);
168
+ }
169
+ async function withRuntimeLock(paths, runtimeId, operation) {
170
+ await ensureDir(paths.controllerRuntimeLocks);
171
+ const file = path.join(paths.controllerRuntimeLocks, `${runtimeId}.lock`);
172
+ const owner = randomBytes(12).toString("hex");
173
+ let handle;
174
+ for (let attempt = 0; attempt < 3_000; attempt += 1) {
175
+ try {
176
+ handle = await open(file, "wx", 0o600);
177
+ try {
178
+ await handle.writeFile(`${JSON.stringify({ owner, pid: process.pid, created_at: new Date().toISOString() })}\n`);
179
+ }
180
+ catch (error) {
181
+ await handle.close().catch(() => { });
182
+ handle = undefined;
183
+ await removeIfExists(file);
184
+ throw error;
185
+ }
186
+ break;
187
+ }
188
+ catch (error) {
189
+ if (error?.code !== "EEXIST")
190
+ throw error;
191
+ if (await staleRuntimeLock(file)) {
192
+ if (!await reclaimStaleLock(file, staleRuntimeLock))
193
+ await delay(100);
194
+ continue;
195
+ }
196
+ await delay(100);
197
+ }
198
+ }
199
+ if (!handle) {
200
+ throw new HitchError("timed out waiting for controller runtime lock", {
201
+ code: "controller_runtime_locked",
202
+ exitCode: 5,
203
+ });
204
+ }
205
+ try {
206
+ return await operation();
207
+ }
208
+ finally {
209
+ await handle.close().catch(() => { });
210
+ const current = await readJSON(file, null).catch(() => null);
211
+ if (current?.owner === owner)
212
+ await removeIfExists(file);
213
+ }
214
+ }
215
+ async function staleRuntimeLock(file) {
216
+ let lock;
217
+ try {
218
+ lock = JSON.parse(await readFile(file, "utf8"));
219
+ }
220
+ catch {
221
+ try {
222
+ return Date.now() - (await stat(file)).mtimeMs > 2_000;
223
+ }
224
+ catch {
225
+ return true;
226
+ }
227
+ }
228
+ if (!Number.isInteger(lock?.pid))
229
+ return true;
230
+ try {
231
+ process.kill(lock.pid, 0);
232
+ return false;
233
+ }
234
+ catch (error) {
235
+ return error?.code === "ESRCH";
236
+ }
237
+ }
238
+ async function loadManifest(directory) {
239
+ const raw = await readJSON(path.join(directory, "manifest.json"), null);
240
+ if (raw === null) {
241
+ throw new ControllerRuntimeIntegrityError(`controller runtime bundle is missing its manifest: ${directory}`);
242
+ }
243
+ return validateControllerRuntimeManifest(raw);
244
+ }
245
+ function manifestDigest(manifest) {
246
+ const encoding = canonicalEncodeManifest({ entrypoints: manifest.entrypoints, files: manifest.files });
247
+ return `sha256:${createHash("sha256").update(encoding).digest("hex")}`;
248
+ }
249
+ /**
250
+ * Verify and return a controller runtime bundle by id. A missing or corrupt
251
+ * expected runtime must not silently fall back to the installed Hitch version
252
+ * (spec §4.6) — it fails with `controller_runtime_integrity_mismatch`.
253
+ *
254
+ * The canonical manifest digest must equal BOTH the manifest's declared
255
+ * `runtime_id` and the directory id, so a runtime id can never be rebound to a
256
+ * different payload: editing the payload and rewriting the manifest's digest
257
+ * field is rejected because the recomputed digest no longer matches the
258
+ * declared `runtime_id` (spec §4.4, §11.1).
259
+ */
260
+ export async function useControllerRuntimeById(paths, runtimeId) {
261
+ const directory = path.join(paths.controllerRuntimes, runtimeId);
262
+ const manifest = await loadManifest(directory).catch(() => {
263
+ throw new HitchError(`controller runtime integrity mismatch for ${runtimeId}`, {
264
+ code: "controller_runtime_integrity_mismatch",
265
+ exitCode: 5,
266
+ });
267
+ });
268
+ const expectedId = `sha256:${runtimeId}`;
269
+ const recomputedDigest = manifestDigest(manifest);
270
+ if (manifest.runtime_id !== expectedId || recomputedDigest !== expectedId || recomputedDigest !== manifest.runtime_id) {
271
+ throw new HitchError(`controller runtime integrity mismatch for ${runtimeId}: manifest runtime_id ${manifest.runtime_id} does not match the recomputed identity ${recomputedDigest}`, { code: "controller_runtime_integrity_mismatch", exitCode: 5 });
272
+ }
273
+ try {
274
+ await verifyRuntimePayload(path.join(directory, "payload"), manifest);
275
+ }
276
+ catch (error) {
277
+ throw new HitchError(`controller runtime integrity mismatch for ${runtimeId}: ${error.message}`, {
278
+ code: "controller_runtime_integrity_mismatch",
279
+ exitCode: 5,
280
+ cause: error,
281
+ });
282
+ }
283
+ return {
284
+ runtime_id: `sha256:${runtimeId}`,
285
+ directory,
286
+ manifest,
287
+ cache_hit: true,
288
+ manifest_digest: manifestDigest(manifest),
289
+ };
290
+ }
291
+ export async function writeRuntimeReference(evalDirectory, use) {
292
+ const ref = {
293
+ schema_version: SCHEMA_VERSION,
294
+ storage: "controller-runtime-ref-v1",
295
+ runtime_id: use.runtime_id,
296
+ manifest_digest: use.manifest_digest,
297
+ created_at: new Date().toISOString(),
298
+ };
299
+ const file = path.join(evalDirectory, "runtime.ref.json");
300
+ await atomicWriteJSON(file, ref);
301
+ return file;
302
+ }
303
+ /** Detect which runtime storage kind an eval record uses (spec §4.7, §9). */
304
+ export async function inspectEvalRuntimeKind(evalDirectory) {
305
+ const ref = await readJSON(path.join(evalDirectory, "runtime.ref.json"), null);
306
+ if (ref?.storage === "controller-runtime-ref-v1")
307
+ return "controller-runtime-ref-v1";
308
+ try {
309
+ const info = await stat(path.join(evalDirectory, "runtime"));
310
+ if (info.isDirectory())
311
+ return "embedded-runtime-v1";
312
+ }
313
+ catch {
314
+ // Not an embedded runtime.
315
+ }
316
+ return "none";
317
+ }
318
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/controller-runtime/store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE5K,OAAO,EACL,+BAA+B,EAC/B,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,iCAAiC,EAAE,MAAM,oBAAoB,CAAC;AAGvE,yFAAyF;AACzF,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,EAAE,CAAC;AAkB1C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,EAAE,IAAI,EAAE,WAAW,GAAG,YAAY,EAAE,KAAK,GAAG,qBAAqB,EAA4B;IAE7F,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,UAAU,CAAC,2DAA2D,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IACrI,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,uEAAuE;IACvE,sEAAsE;IACtE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACrE,oEAAoE;IACpE,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,OAAO,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;YAChE,OAAO,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAChF,CAAC;AACH,CAAC;AAOD,KAAK,UAAU,YAAY,CAAC,WAAmB,EAAE,KAA2B,EAAE,WAAmB;IAC/F,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;IACrF,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAE9D,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,mBAAmB,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtH,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,qEAAqE;IACrE,qDAAqD;IACrD,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,kBAAkB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,WAAW,CAAC,eAAe,EAAE,kBAAkB,EAAE,KAAK,CAAC,CAAC;IAE9D,uEAAuE;IACvE,2CAA2C;IAC3C,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC;IACxF,IAAI,UAAU,CAAC,SAAS,KAAK,UAAU,CAAC,SAAS,EAAE,CAAC;QAClD,MAAM,IAAI,+BAA+B,CAAC,oDAAoD,CAAC,CAAC;IAClG,CAAC;IACD,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAChF,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,UAAkB,EAAE,eAAuB,EAAE,KAA2B;IACjG,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACvE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;QAC3C,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IACvF,CAAC;AACH,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,KAAiB,EAAE,OAAsB;IAC3E,MAAM,SAAS,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3E,6EAA6E;IAC7E,0EAA0E;IAC1E,iDAAiD;IACjD,IAAI,MAAM,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,MAAM,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAAoB,EAAE,IAAI,KAAK,uCAAuC;gBAAE,MAAM,KAAK,CAAC;YACzF,uEAAuE;YACvE,sEAAsE;YACtE,8DAA8D;YAC9D,MAAM,wBAAwB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC7C,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,EAAE,IAAI,KAAK,WAAW,IAAK,KAA+B,EAAE,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;QAC/H,uEAAuE;IACzE,CAAC;IACD,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;QACjD,MAAM,wBAAwB,CAAC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3E,gEAAgE;QAChE,MAAM,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;QACxE,OAAO;YACL,UAAU,EAAE,UAAU,OAAO,CAAC,SAAS,EAAE;YACzC,SAAS,EAAE,WAAW;YACtB,QAAQ;YACR,SAAS,EAAE,KAAK;YAChB,eAAe,EAAE,cAAc,CAAC,QAAQ,CAAC;SAC1C,CAAC;IACJ,CAAC;IACD,OAAO,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5D,CAAC;AAED,KAAK,UAAU,wBAAwB,CAAC,KAAiB,EAAE,WAAmB,EAAE,SAAiB;IAC/F,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,mBAAmB,SAAS,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChH,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1C,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,mEAAmE;QACnE,wEAAwE;QACxE,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAChD,MAAM,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO;QAChE,MAAM,KAAK,CAAC;IACd,CAAC;IACD,mEAAmE;IACnE,mDAAmD;AACrD,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QACtE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,wBAAwB,CAAC,SAAiB,EAAE,aAAqB;IAC9E,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO;IACzC,MAAM,KAAK,GAAa,CAAC,SAAS,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,EAAY,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,MAAM,eAAe,GAAG,iBAAiB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBAC/D,sEAAsE;gBACtE,gEAAgE;gBAChE,MAAM,YAAY,GAAG,eAAe,KAAK,aAAa,CAAC;gBACvD,MAAM,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,SAAiB,EAAE,QAAgB;IAC5D,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;AAClE,CAAC;AAED,KAAK,UAAU,eAAe,CAAI,KAAiB,EAAE,SAAiB,EAAE,SAA2B;IACjG,MAAM,SAAS,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,SAAS,OAAO,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,MAAoD,CAAC;IACzD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACpD,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YACvC,IAAI,CAAC;gBACH,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;YACnH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACrC,MAAM,GAAG,SAAS,CAAC;gBACnB,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;gBAC3B,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,EAAE,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;YACrE,IAAI,MAAM,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,CAAC;oBAAE,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;gBACtE,SAAS;YACX,CAAC;YACD,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,UAAU,CAAC,+CAA+C,EAAE;YACpE,IAAI,EAAE,2BAA2B;YACjC,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,EAAE,CAAC;IAC3B,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAA6B,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACzF,IAAI,OAAO,EAAE,KAAK,KAAK,KAAK;YAAE,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,IAAI,IAA8B,CAAC;IACnC,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAsB,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAa,EAAE,CAAC,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAQ,KAA+B,EAAE,IAAI,KAAK,OAAO,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,SAAiB;IAC3C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAU,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,CAAC;IACjF,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,+BAA+B,CAAC,sDAAsD,SAAS,EAAE,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,iCAAiC,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,cAAc,CAAC,QAAmC;IACzD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IACvG,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACzE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAAiB,EAAE,SAAiB;IACjF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACxD,MAAM,IAAI,UAAU,CAAC,6CAA6C,SAAS,EAAE,EAAE;YAC7E,IAAI,EAAE,uCAAuC;YAC7C,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,UAAU,SAAS,EAAE,CAAC;IACzC,MAAM,gBAAgB,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAClD,IAAI,QAAQ,CAAC,UAAU,KAAK,UAAU,IAAI,gBAAgB,KAAK,UAAU,IAAI,gBAAgB,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC;QACtH,MAAM,IAAI,UAAU,CAClB,6CAA6C,SAAS,yBAAyB,QAAQ,CAAC,UAAU,2CAA2C,gBAAgB,EAAE,EAC/J,EAAE,IAAI,EAAE,uCAAuC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAC/D,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,UAAU,CAAC,6CAA6C,SAAS,KAAM,KAAe,CAAC,OAAO,EAAE,EAAE;YAC1G,IAAI,EAAE,uCAAuC;YAC7C,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,UAAU,EAAE,UAAU,SAAS,EAAE;QACjC,SAAS;QACT,QAAQ;QACR,SAAS,EAAE,IAAI;QACf,eAAe,EAAE,cAAc,CAAC,QAAQ,CAAC;KAC1C,CAAC;AACJ,CAAC;AAUD,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,aAAqB,EAAE,GAA+B;IAChG,MAAM,GAAG,GAA+B;QACtC,cAAc,EAAE,cAAc;QAC9B,OAAO,EAAE,2BAA2B;QACpC,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;IAC1D,MAAM,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,aAAqB;IAChE,MAAM,GAAG,GAAG,MAAM,QAAQ,CAA+B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,kBAAkB,CAAC,EAAE,IAAI,CAAC,CAAC;IAC7G,IAAI,GAAG,EAAE,OAAO,KAAK,2BAA2B;QAAE,OAAO,2BAA2B,CAAC;IACrF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;QAC7D,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO,qBAAqB,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,108 @@
1
+ import { randomBytes, timingSafeEqual } from "node:crypto";
2
+ import { open, readFile, rm } from "node:fs/promises";
3
+ import { HitchError, SCHEMA_VERSION, reclaimStaleLock, writePrivateFile } from "../foundation/index.js";
4
+ export async function acquireInstanceLock(file, instanceId) {
5
+ const owner = {
6
+ schema_version: SCHEMA_VERSION,
7
+ instance_id: instanceId,
8
+ pid: process.pid,
9
+ created_at: new Date().toISOString(),
10
+ };
11
+ for (let attempt = 0; attempt < 4; attempt += 1) {
12
+ try {
13
+ const handle = await open(file, "wx", 0o600);
14
+ try {
15
+ await handle.writeFile(`${JSON.stringify(owner)}\n`);
16
+ await handle.sync();
17
+ }
18
+ finally {
19
+ await handle.close();
20
+ }
21
+ return;
22
+ }
23
+ catch (error) {
24
+ if (error?.code !== "EEXIST")
25
+ throw error;
26
+ let existing;
27
+ try {
28
+ existing = JSON.parse(await readFile(file, "utf8"));
29
+ }
30
+ catch (readError) {
31
+ if (attempt < 3) {
32
+ await new Promise((resolve) => setTimeout(resolve, 25));
33
+ continue;
34
+ }
35
+ throw new HitchError("daemon lock exists but its owner record is unreadable", { code: "daemon_lock_invalid", exitCode: 12, cause: readError });
36
+ }
37
+ if (processIsAlive(existing.pid)) {
38
+ throw new HitchError(`another daemon owns this root (pid ${existing.pid})`, { code: "already_running", exitCode: 2 });
39
+ }
40
+ const reclaimed = await reclaimStaleLock(file, async (candidate) => {
41
+ let current;
42
+ try {
43
+ current = JSON.parse(await readFile(candidate, "utf8"));
44
+ }
45
+ catch (readError) {
46
+ if (readError?.code === "ENOENT")
47
+ return false;
48
+ throw new HitchError("daemon lock exists but its owner record is unreadable", {
49
+ code: "daemon_lock_invalid",
50
+ exitCode: 12,
51
+ cause: readError,
52
+ });
53
+ }
54
+ return !processIsAlive(current.pid);
55
+ });
56
+ if (!reclaimed)
57
+ await new Promise((resolve) => setTimeout(resolve, 25));
58
+ }
59
+ }
60
+ throw new HitchError("could not acquire daemon root lock", { code: "daemon_lock_failed", exitCode: 12 });
61
+ }
62
+ export async function releaseInstanceLock(file, instanceId) {
63
+ let owner;
64
+ try {
65
+ owner = JSON.parse(await readFile(file, "utf8"));
66
+ }
67
+ catch (error) {
68
+ if (error?.code === "ENOENT")
69
+ return;
70
+ return;
71
+ }
72
+ if (owner.instance_id === instanceId)
73
+ await rm(file, { force: true });
74
+ }
75
+ function processIsAlive(pid) {
76
+ if (!Number.isInteger(pid) || pid <= 0)
77
+ return false;
78
+ try {
79
+ process.kill(pid, 0);
80
+ return true;
81
+ }
82
+ catch (error) {
83
+ return error?.code === "EPERM";
84
+ }
85
+ }
86
+ export async function ensureToken(file) {
87
+ try {
88
+ const existing = (await readFile(file, "utf8")).trim();
89
+ if (existing.length >= 32)
90
+ return existing;
91
+ }
92
+ catch (error) {
93
+ if (error?.code !== "ENOENT")
94
+ throw error;
95
+ }
96
+ const token = randomBytes(32).toString("hex");
97
+ await writePrivateFile(file, `${token}\n`);
98
+ return token;
99
+ }
100
+ export function authorized(request, token) {
101
+ const value = request.headers.authorization || "";
102
+ if (!value.startsWith("Bearer "))
103
+ return false;
104
+ const supplied = Buffer.from(value.slice(7));
105
+ const expected = Buffer.from(token);
106
+ return supplied.length === expected.length && timingSafeEqual(supplied, expected);
107
+ }
108
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/daemon/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { HitchError, readJSON, statePaths } from "../foundation/index.js";
3
+ export async function daemonClient(root) {
4
+ const paths = statePaths(root);
5
+ const state = await readJSON(paths.daemon, null);
6
+ if (!state?.port)
7
+ throw new Error("daemon is not running");
8
+ const token = (await readFile(paths.token, "utf8")).trim();
9
+ const performRequest = async (pathname, options = {}) => {
10
+ const headers = new Headers(options.headers);
11
+ headers.set("authorization", `Bearer ${token}`);
12
+ if (options.body && !headers.has("content-type"))
13
+ headers.set("content-type", "application/json");
14
+ const response = await fetch(`http://127.0.0.1:${state.port}${pathname}`, { ...options, headers });
15
+ const contentType = response.headers.get("content-type") || "";
16
+ const mediaType = (contentType.split(";", 1)[0] || "").trim().toLowerCase();
17
+ const isJSONDocument = mediaType === "application/json" || mediaType.endsWith("+json");
18
+ const payload = isJSONDocument ? await response.json() : await response.text();
19
+ if (!response.ok) {
20
+ const errorPayload = typeof payload === "object" && payload !== null ? payload : {};
21
+ const message = errorPayload.error?.message || `daemon request failed (${response.status})`;
22
+ const error = new HitchError(message, {
23
+ code: errorPayload.error?.code || httpErrorCode(response.status),
24
+ exitCode: Number.isInteger(errorPayload.error?.exit_code)
25
+ ? errorPayload.error.exit_code
26
+ : httpExitCode(response.status),
27
+ });
28
+ error.status = response.status;
29
+ throw error;
30
+ }
31
+ return { payload, headers: response.headers, status: response.status };
32
+ };
33
+ const request = async (pathname, options) => (await performRequest(pathname, options)).payload;
34
+ return { state, request, requestWithMetadata: performRequest };
35
+ }
36
+ export async function probeDaemonHealth(root) {
37
+ const state = await readJSON(statePaths(root).daemon, null);
38
+ if (!state?.port)
39
+ return null;
40
+ try {
41
+ const response = await fetch(`http://127.0.0.1:${state.port}/health`, { signal: AbortSignal.timeout(1_000) });
42
+ if (!response.ok)
43
+ return null;
44
+ const health = await response.json();
45
+ return health.instance_id === state.instance_id ? health : null;
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
51
+ export async function readDaemonLogs(root, lines) {
52
+ let content = "";
53
+ try {
54
+ content = await readFile(statePaths(root).log, "utf8");
55
+ }
56
+ catch (error) {
57
+ if (error?.code !== "ENOENT")
58
+ throw error;
59
+ }
60
+ return content.trimEnd().split(/\r?\n/).slice(-lines).join("\n");
61
+ }
62
+ function httpExitCode(status) {
63
+ if (status === 400)
64
+ return 2;
65
+ if (status === 404)
66
+ return 3;
67
+ return 12;
68
+ }
69
+ function httpErrorCode(status) {
70
+ if (status === 400)
71
+ return "invalid_input";
72
+ if (status === 404)
73
+ return "not_found";
74
+ return "daemon_request_failed";
75
+ }
76
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/daemon/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { Scheduler } from "./scheduler.js";
2
+ export { DaemonServer } from "./server.js";
3
+ export { daemonClient, probeDaemonHealth, readDaemonLogs } from "./client.js";
4
+ export { startDetachedDaemon } from "./launcher.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { spawn } from "node:child_process";
2
+ import { openSync } from "node:fs";
3
+ import { ensureDir, statePaths } from "../foundation/index.js";
4
+ export async function startDetachedDaemon(options) {
5
+ const { root, executable, port, maxConcurrent } = options;
6
+ const paths = statePaths(root);
7
+ await ensureDir(root);
8
+ const stdout = openSync(paths.log, "a", 0o600);
9
+ const stderr = openSync(paths.errorLog, "a", 0o600);
10
+ const child = spawn(process.execPath, [
11
+ executable,
12
+ "--root", root,
13
+ "daemon", "serve",
14
+ "--port", String(port),
15
+ "--max-concurrent", String(maxConcurrent),
16
+ ], {
17
+ detached: true,
18
+ stdio: ["ignore", stdout, stderr],
19
+ windowsHide: true,
20
+ });
21
+ child.unref();
22
+ return { pid: child.pid, errorLog: paths.errorLog };
23
+ }
24
+ //# sourceMappingURL=launcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.js","sourceRoot":"","sources":["../../../src/daemon/launcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAS/D,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAA8B;IACtE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAC1D,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACtB,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;QACpC,UAAU;QACV,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,OAAO;QACjB,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC,aAAa,CAAC;KAC1C,EAAE;QACD,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QACjC,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;AACtD,CAAC"}