agent-hitch 0.2.0 → 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 +16 -10
  2. package/README.zh-CN.md +13 -8
  3. package/dist/bin/hitch.js +1 -1
  4. package/dist/bin/hitch.js.map +1 -1
  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 +1 -1
  8. package/dist/scripts/check-release.js.map +1 -1
  9. package/dist/src/adapters/catalog.js +55 -0
  10. package/dist/src/adapters/catalog.js.map +1 -0
  11. package/dist/src/adapters/contract.js +2 -0
  12. package/dist/src/adapters/contract.js.map +1 -0
  13. package/dist/src/adapters/discovery.js +22 -0
  14. package/dist/src/adapters/discovery.js.map +1 -0
  15. package/dist/src/adapters/index.js +3 -0
  16. package/dist/src/adapters/index.js.map +1 -0
  17. package/dist/src/adapters/providers/claude.js +69 -0
  18. package/dist/src/adapters/providers/claude.js.map +1 -0
  19. package/dist/src/adapters/providers/codex.js +74 -0
  20. package/dist/src/adapters/providers/codex.js.map +1 -0
  21. package/dist/src/adapters/providers/deepseek.js +51 -0
  22. package/dist/src/adapters/providers/deepseek.js.map +1 -0
  23. package/dist/src/adapters/providers/opencode.js +73 -0
  24. package/dist/src/adapters/providers/opencode.js.map +1 -0
  25. package/dist/src/adapters/providers/pi.js +82 -0
  26. package/dist/src/adapters/providers/pi.js.map +1 -0
  27. package/dist/src/adapters/providers/shared.js +82 -0
  28. package/dist/src/adapters/providers/shared.js.map +1 -0
  29. package/dist/src/artifacts/index.js +3 -0
  30. package/dist/src/artifacts/index.js.map +1 -0
  31. package/dist/src/artifacts/integrity.js +188 -0
  32. package/dist/src/artifacts/integrity.js.map +1 -0
  33. package/dist/src/artifacts/preparer.js +379 -0
  34. package/dist/src/artifacts/preparer.js.map +1 -0
  35. package/dist/src/artifacts/store.js +87 -0
  36. package/dist/src/artifacts/store.js.map +1 -0
  37. package/dist/src/artifacts/types.js +2 -0
  38. package/dist/src/artifacts/types.js.map +1 -0
  39. package/dist/src/backends/contract.js +2 -0
  40. package/dist/src/backends/contract.js.map +1 -0
  41. package/dist/src/{harbor-backend.js → backends/harbor/backend.js} +39 -14
  42. package/dist/src/backends/harbor/backend.js.map +1 -0
  43. package/dist/src/backends/harbor/index.js +4 -0
  44. package/dist/src/backends/harbor/index.js.map +1 -0
  45. package/dist/src/backends/harbor/local-git-transport.js +447 -0
  46. package/dist/src/backends/harbor/local-git-transport.js.map +1 -0
  47. package/dist/src/{eval-tools.js → backends/harbor/tools.js} +2 -6
  48. package/dist/src/backends/harbor/tools.js.map +1 -0
  49. package/dist/src/backends/index.js +4 -0
  50. package/dist/src/backends/index.js.map +1 -0
  51. package/dist/src/cli/arguments.js +123 -0
  52. package/dist/src/cli/arguments.js.map +1 -0
  53. package/dist/src/cli/commands/compare.js +55 -0
  54. package/dist/src/cli/commands/compare.js.map +1 -0
  55. package/dist/src/cli/commands/daemon.js +106 -0
  56. package/dist/src/cli/commands/daemon.js.map +1 -0
  57. package/dist/src/cli/commands/eval.js +126 -0
  58. package/dist/src/cli/commands/eval.js.map +1 -0
  59. package/dist/src/cli/commands/feedback.js +84 -0
  60. package/dist/src/cli/commands/feedback.js.map +1 -0
  61. package/dist/src/cli/commands/inspect.js +20 -0
  62. package/dist/src/cli/commands/inspect.js.map +1 -0
  63. package/dist/src/cli/commands/list.js +17 -0
  64. package/dist/src/cli/commands/list.js.map +1 -0
  65. package/dist/src/cli/commands/prepare.js +21 -0
  66. package/dist/src/cli/commands/prepare.js.map +1 -0
  67. package/dist/src/cli/commands/resolve.js +17 -0
  68. package/dist/src/cli/commands/resolve.js.map +1 -0
  69. package/dist/src/cli/commands/run.js +83 -0
  70. package/dist/src/cli/commands/run.js.map +1 -0
  71. package/dist/src/cli/commands/runs.js +45 -0
  72. package/dist/src/cli/commands/runs.js.map +1 -0
  73. package/dist/src/cli/commands/trajectory.js +31 -0
  74. package/dist/src/cli/commands/trajectory.js.map +1 -0
  75. package/dist/src/cli/commands/workspace.js +44 -0
  76. package/dist/src/cli/commands/workspace.js.map +1 -0
  77. package/dist/src/cli/index.js +2 -0
  78. package/dist/src/cli/index.js.map +1 -0
  79. package/dist/src/cli/main.js +48 -0
  80. package/dist/src/cli/main.js.map +1 -0
  81. package/dist/src/cli/output.js +96 -0
  82. package/dist/src/cli/output.js.map +1 -0
  83. package/dist/src/controller-runtime/index.js +3 -0
  84. package/dist/src/controller-runtime/index.js.map +1 -0
  85. package/dist/src/controller-runtime/store.js +2 -7
  86. package/dist/src/controller-runtime/store.js.map +1 -1
  87. package/dist/src/daemon/auth.js +108 -0
  88. package/dist/src/daemon/auth.js.map +1 -0
  89. package/dist/src/daemon/client.js +76 -0
  90. package/dist/src/daemon/client.js.map +1 -0
  91. package/dist/src/daemon/index.js +5 -0
  92. package/dist/src/daemon/index.js.map +1 -0
  93. package/dist/src/daemon/launcher.js +24 -0
  94. package/dist/src/daemon/launcher.js.map +1 -0
  95. package/dist/src/{scheduler.js → daemon/scheduler.js} +6 -7
  96. package/dist/src/daemon/scheduler.js.map +1 -0
  97. package/dist/src/{daemon.js → daemon/server.js} +10 -155
  98. package/dist/src/daemon/server.js.map +1 -0
  99. package/dist/src/domain/artifacts.js +2 -0
  100. package/dist/src/domain/artifacts.js.map +1 -0
  101. package/dist/src/domain/controller-runtime.js +2 -0
  102. package/dist/src/domain/controller-runtime.js.map +1 -0
  103. package/dist/src/domain/eval-records.js +2 -0
  104. package/dist/src/domain/eval-records.js.map +1 -0
  105. package/dist/src/domain/evals.js +2 -0
  106. package/dist/src/domain/evals.js.map +1 -0
  107. package/dist/src/domain/feedback.js +2 -0
  108. package/dist/src/domain/feedback.js.map +1 -0
  109. package/dist/src/domain/{types.js → ids.js} +1 -1
  110. package/dist/src/domain/ids.js.map +1 -0
  111. package/dist/src/domain/index.js +11 -0
  112. package/dist/src/domain/index.js.map +1 -0
  113. package/dist/src/domain/revisions.js +2 -0
  114. package/dist/src/domain/revisions.js.map +1 -0
  115. package/dist/src/domain/runs.js +3 -0
  116. package/dist/src/domain/runs.js.map +1 -0
  117. package/dist/src/domain/trajectories.js +2 -0
  118. package/dist/src/domain/trajectories.js.map +1 -0
  119. package/dist/src/domain/{validate.js → validation.js} +194 -5
  120. package/dist/src/domain/validation.js.map +1 -0
  121. package/dist/src/domain/workspaces.js +2 -0
  122. package/dist/src/domain/workspaces.js.map +1 -0
  123. package/dist/src/evals/events.js +67 -0
  124. package/dist/src/evals/events.js.map +1 -0
  125. package/dist/src/evals/index.js +5 -0
  126. package/dist/src/evals/index.js.map +1 -0
  127. package/dist/src/evals/records.js +55 -0
  128. package/dist/src/evals/records.js.map +1 -0
  129. package/dist/src/evals/request.js +109 -0
  130. package/dist/src/evals/request.js.map +1 -0
  131. package/dist/src/evals/service.js +227 -0
  132. package/dist/src/evals/service.js.map +1 -0
  133. package/dist/src/evals/trial-import.js +394 -0
  134. package/dist/src/evals/trial-import.js.map +1 -0
  135. package/dist/src/feedback/index.js +2 -0
  136. package/dist/src/feedback/index.js.map +1 -0
  137. package/dist/src/feedback/service.js +3 -4
  138. package/dist/src/feedback/service.js.map +1 -1
  139. package/dist/src/{config.js → foundation/config.js} +1 -0
  140. package/dist/src/foundation/config.js.map +1 -0
  141. package/dist/src/foundation/errors.js.map +1 -0
  142. package/dist/src/foundation/executable.js +135 -0
  143. package/dist/src/foundation/executable.js.map +1 -0
  144. package/dist/src/foundation/fs.js.map +1 -0
  145. package/dist/src/foundation/hash.js +24 -0
  146. package/dist/src/foundation/hash.js.map +1 -0
  147. package/dist/src/foundation/index.js +11 -0
  148. package/dist/src/foundation/index.js.map +1 -0
  149. package/dist/src/foundation/line-stream.js.map +1 -0
  150. package/dist/src/foundation/locks.js +114 -0
  151. package/dist/src/foundation/locks.js.map +1 -0
  152. package/dist/src/{package-root.js → foundation/package-root.js} +3 -2
  153. package/dist/src/foundation/package-root.js.map +1 -0
  154. package/dist/src/foundation/process.js.map +1 -0
  155. package/dist/src/revisions/index.js +4 -0
  156. package/dist/src/revisions/index.js.map +1 -0
  157. package/dist/src/{harness-reference.js → revisions/reference.js} +16 -2
  158. package/dist/src/revisions/reference.js.map +1 -0
  159. package/dist/src/revisions/resolver.js +25 -0
  160. package/dist/src/revisions/resolver.js.map +1 -0
  161. package/dist/src/revisions/sources/git.js +180 -0
  162. package/dist/src/revisions/sources/git.js.map +1 -0
  163. package/dist/src/revisions/sources/installed.js +45 -0
  164. package/dist/src/revisions/sources/installed.js.map +1 -0
  165. package/dist/src/revisions/sources/npm.js +97 -0
  166. package/dist/src/revisions/sources/npm.js.map +1 -0
  167. package/dist/src/runs/compare.js +132 -0
  168. package/dist/src/runs/compare.js.map +1 -0
  169. package/dist/src/{events.js → runs/events.js} +1 -2
  170. package/dist/src/runs/events.js.map +1 -0
  171. package/dist/src/{engine.js → runs/executor.js} +166 -151
  172. package/dist/src/runs/executor.js.map +1 -0
  173. package/dist/src/runs/finalizer.js +22 -0
  174. package/dist/src/runs/finalizer.js.map +1 -0
  175. package/dist/src/runs/identity.js +35 -0
  176. package/dist/src/runs/identity.js.map +1 -0
  177. package/dist/src/runs/index.js +11 -0
  178. package/dist/src/runs/index.js.map +1 -0
  179. package/dist/src/runs/manifest.js +70 -0
  180. package/dist/src/runs/manifest.js.map +1 -0
  181. package/dist/src/runs/outcome.js +49 -0
  182. package/dist/src/runs/outcome.js.map +1 -0
  183. package/dist/src/runs/query.js +104 -0
  184. package/dist/src/runs/query.js.map +1 -0
  185. package/dist/src/runs/queued.js +54 -0
  186. package/dist/src/runs/queued.js.map +1 -0
  187. package/dist/src/runs/records.js +288 -0
  188. package/dist/src/runs/records.js.map +1 -0
  189. package/dist/src/runs/request.js +169 -0
  190. package/dist/src/runs/request.js.map +1 -0
  191. package/dist/src/trajectories/format.js +1 -1
  192. package/dist/src/trajectories/format.js.map +1 -1
  193. package/dist/src/trajectories/index.js +7 -0
  194. package/dist/src/trajectories/index.js.map +1 -0
  195. package/dist/src/trajectories/projector.js +1 -1
  196. package/dist/src/trajectories/projector.js.map +1 -1
  197. package/dist/src/trajectories/provider-capture.js +133 -0
  198. package/dist/src/trajectories/provider-capture.js.map +1 -0
  199. package/dist/src/trajectories/providers/deepseek.js +179 -0
  200. package/dist/src/trajectories/providers/deepseek.js.map +1 -0
  201. package/dist/src/trajectories/store.js +148 -8
  202. package/dist/src/trajectories/store.js.map +1 -1
  203. package/dist/src/workspaces/copy.js +142 -0
  204. package/dist/src/workspaces/copy.js.map +1 -0
  205. package/dist/src/workspaces/digest.js +47 -0
  206. package/dist/src/workspaces/digest.js.map +1 -0
  207. package/dist/src/workspaces/git.js +164 -0
  208. package/dist/src/workspaces/git.js.map +1 -0
  209. package/dist/src/workspaces/index.js +6 -0
  210. package/dist/src/workspaces/index.js.map +1 -0
  211. package/dist/src/workspaces/lifecycle.js +313 -0
  212. package/dist/src/workspaces/lifecycle.js.map +1 -0
  213. package/dist/src/workspaces/planner.js +80 -0
  214. package/dist/src/workspaces/planner.js.map +1 -0
  215. package/dist/src/workspaces/store.js +25 -0
  216. package/dist/src/workspaces/store.js.map +1 -0
  217. package/dist/src/workspaces/types.js +4 -0
  218. package/dist/src/workspaces/types.js.map +1 -0
  219. package/dist/src/workspaces/utils.js +56 -0
  220. package/dist/src/workspaces/utils.js.map +1 -0
  221. package/docs/schemas/eval-request.schema.json +2 -0
  222. package/docs/schemas/eval-result.schema.json +36 -1
  223. package/docs/schemas/local-git-transport-manifest.schema.json +34 -0
  224. package/docs/schemas/result.schema.json +9 -0
  225. package/docs/schemas/run-context.schema.json +39 -0
  226. package/docs/schemas/run-manifest.schema.json +81 -0
  227. package/docs/schemas/run-request.schema.json +16 -1
  228. package/docs/schemas/trajectory-ref.schema.json +66 -23
  229. package/integrations/harbor/hitch_harbor_agent.py +375 -1
  230. package/package.json +21 -3
  231. package/dist/src/adapters.js +0 -461
  232. package/dist/src/adapters.js.map +0 -1
  233. package/dist/src/artifacts.js +0 -1081
  234. package/dist/src/artifacts.js.map +0 -1
  235. package/dist/src/cli.js +0 -699
  236. package/dist/src/cli.js.map +0 -1
  237. package/dist/src/config.js.map +0 -1
  238. package/dist/src/daemon.js.map +0 -1
  239. package/dist/src/domain/types.js.map +0 -1
  240. package/dist/src/domain/validate.js.map +0 -1
  241. package/dist/src/engine.js.map +0 -1
  242. package/dist/src/errors.js.map +0 -1
  243. package/dist/src/eval-tools.js.map +0 -1
  244. package/dist/src/evals.js +0 -313
  245. package/dist/src/evals.js.map +0 -1
  246. package/dist/src/events.js.map +0 -1
  247. package/dist/src/fs.js.map +0 -1
  248. package/dist/src/harbor-backend.js.map +0 -1
  249. package/dist/src/harness-reference.js.map +0 -1
  250. package/dist/src/line-stream.js.map +0 -1
  251. package/dist/src/locks.js +0 -38
  252. package/dist/src/locks.js.map +0 -1
  253. package/dist/src/package-root.js.map +0 -1
  254. package/dist/src/process.js.map +0 -1
  255. package/dist/src/registry.js +0 -81
  256. package/dist/src/registry.js.map +0 -1
  257. package/dist/src/scheduler.js.map +0 -1
  258. package/dist/src/workspaces.js +0 -858
  259. package/dist/src/workspaces.js.map +0 -1
  260. /package/dist/src/{errors.js → foundation/errors.js} +0 -0
  261. /package/dist/src/{fs.js → foundation/fs.js} +0 -0
  262. /package/dist/src/{line-stream.js → foundation/line-stream.js} +0 -0
  263. /package/dist/src/{process.js → foundation/process.js} +0 -0
@@ -0,0 +1,6 @@
1
+ export { WORKSPACE_MODES } from "./types.js";
2
+ export { planWorkspace } from "./planner.js";
3
+ export { abandonPlannedWorkspace, cancelPlannedWorkspace, finalizeWorkspace, inspectWorkspace, markWorkspaceFinalizationFailed, markWorkspaceRunning, prepareWorkspace, recoverInterruptedWorkspace, removeWorkspace } from "./lifecycle.js";
4
+ export { workspaceDigest } from "./digest.js";
5
+ export { workspaceManifestFields, workspaceRecordPath } from "./store.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/workspaces/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,+BAA+B,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7O,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,313 @@
1
+ import { chmod, mkdir, rm } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { HitchError, atomicWriteJSON, invalidInput, readJSON, statePaths } from "../foundation/index.js";
4
+ import { prepareCopy } from "./copy.js";
5
+ import { workspaceDigest } from "./digest.js";
6
+ import { isolatedGitMetadataDigest, prepareWorktree, registeredWorktree, runGit, tryGitOutput } from "./git.js";
7
+ import { withWorkspaceLock, workspaceRecordPath } from "./store.js";
8
+ import { ACTIVE_WORKSPACE_STATES } from "./types.js";
9
+ import { assertRunId, canonicalizePotentialPath, isWithin, pathExists, throwIfAborted } from "./utils.js";
10
+ export async function prepareWorkspace(plan, { recordPath, signal } = {}) {
11
+ if (plan.mode === "shared") {
12
+ const ready = {
13
+ ...plan,
14
+ status: "ready",
15
+ prepared_at: new Date().toISOString(),
16
+ };
17
+ if (recordPath)
18
+ await atomicWriteJSON(recordPath, ready);
19
+ return ready;
20
+ }
21
+ const provisioning = { ...plan, status: "provisioning", provisioning_at: new Date().toISOString() };
22
+ if (recordPath)
23
+ await atomicWriteJSON(recordPath, provisioning);
24
+ let ownsManagedDirectory = false;
25
+ try {
26
+ throwIfAborted(signal);
27
+ await assertManagedPlan(plan);
28
+ await mkdir(path.dirname(plan.managed_directory), { recursive: true, mode: 0o700 });
29
+ await chmod(path.dirname(plan.managed_directory), 0o700);
30
+ if (await pathExists(plan.managed_directory)) {
31
+ throw new HitchError(`managed workspace already exists for ${plan.run_id}`, {
32
+ code: "workspace_already_exists",
33
+ exitCode: 11,
34
+ });
35
+ }
36
+ await mkdir(plan.managed_directory, { mode: 0o700 });
37
+ ownsManagedDirectory = true;
38
+ const preparation = plan.mode === "worktree"
39
+ ? await prepareWorktree(plan, { signal })
40
+ : await prepareCopy(plan, { signal });
41
+ await chmod(plan.managed_directory, 0o700);
42
+ await chmod(plan.execution_root, 0o700);
43
+ const baselineDigest = preparation?.baseline_digest || await workspaceDigest(plan.execution_root, {
44
+ signal,
45
+ excludedTopLevel: gitMetadataExclusion(plan),
46
+ });
47
+ const baselineGitMetadataDigest = plan.mode === "copy" && plan.git
48
+ ? await isolatedGitMetadataDigest(plan.execution_root, { signal })
49
+ : null;
50
+ const preparedAt = new Date().toISOString();
51
+ const ready = {
52
+ ...provisioning,
53
+ status: "ready",
54
+ baseline_digest: baselineDigest,
55
+ baseline_git_metadata_digest: baselineGitMetadataDigest,
56
+ snapshot: { ...plan.snapshot, content_digest: baselineDigest, captured_at: preparedAt },
57
+ retained: true,
58
+ prepared_at: preparedAt,
59
+ };
60
+ if (recordPath)
61
+ await atomicWriteJSON(recordPath, ready);
62
+ return ready;
63
+ }
64
+ catch (error) {
65
+ if (ownsManagedDirectory)
66
+ await cleanupProvisioning(plan).catch(() => { });
67
+ const errno = error;
68
+ const workspaceError = errno?.code === "EEXIST"
69
+ ? new HitchError(`managed workspace already exists for ${plan.run_id}`, {
70
+ code: "workspace_already_exists",
71
+ exitCode: 11,
72
+ cause: error,
73
+ })
74
+ : error;
75
+ const hitchWorkspaceError = workspaceError;
76
+ const failed = {
77
+ ...provisioning,
78
+ status: workspaceError instanceof Error && workspaceError.name === "HitchError" && hitchWorkspaceError.code === "cancelled" ? "cancelled" : "failed",
79
+ retained: false,
80
+ error: { code: hitchWorkspaceError.code || "workspace_provision_failed", message: workspaceError?.message || String(workspaceError) },
81
+ completed_at: new Date().toISOString(),
82
+ };
83
+ if (recordPath)
84
+ await atomicWriteJSON(recordPath, failed);
85
+ if (workspaceError instanceof HitchError)
86
+ throw workspaceError;
87
+ throw new HitchError(`failed to provision isolated workspace: ${workspaceError.message}`, {
88
+ code: "workspace_provision_failed",
89
+ exitCode: 5,
90
+ cause: workspaceError,
91
+ });
92
+ }
93
+ }
94
+ export async function markWorkspaceRunning(workspace, { recordPath } = {}) {
95
+ const running = { ...workspace, status: "running", started_at: new Date().toISOString() };
96
+ if (recordPath)
97
+ await atomicWriteJSON(recordPath, running);
98
+ return running;
99
+ }
100
+ export async function finalizeWorkspace(workspace, { recordPath } = {}) {
101
+ if (!workspace)
102
+ return null;
103
+ if (workspace.mode === "shared") {
104
+ const released = {
105
+ ...workspace,
106
+ status: "released",
107
+ retained: false,
108
+ changed: null,
109
+ finalized_at: new Date().toISOString(),
110
+ };
111
+ if (recordPath)
112
+ await atomicWriteJSON(recordPath, released);
113
+ return released;
114
+ }
115
+ const finalDigest = await workspaceDigest(workspace.execution_root, {
116
+ excludedTopLevel: gitMetadataExclusion(workspace),
117
+ });
118
+ let headAfter = null;
119
+ let gitStatus = null;
120
+ let finalGitMetadataDigest = null;
121
+ if (workspace.git) {
122
+ headAfter = await tryGitOutput(["-C", workspace.execution_root, "rev-parse", "--verify", "HEAD^{commit}"]);
123
+ gitStatus = await tryGitOutput(["-C", workspace.execution_root, "status", "--porcelain=v1", "--untracked-files=all"]);
124
+ if (workspace.mode === "copy")
125
+ finalGitMetadataDigest = await isolatedGitMetadataDigest(workspace.execution_root);
126
+ }
127
+ const gitStateChanged = workspace.git
128
+ ? gitStatus === null
129
+ || (workspace.git.head ? !headAfter || headAfter !== workspace.git.head : Boolean(headAfter))
130
+ || (workspace.mode === "copy" && finalGitMetadataDigest !== workspace.baseline_git_metadata_digest)
131
+ : false;
132
+ const retained = {
133
+ ...workspace,
134
+ status: "retained",
135
+ retained: true,
136
+ changed: finalDigest !== workspace.baseline_digest || gitStateChanged,
137
+ final_digest: finalDigest,
138
+ ...(finalGitMetadataDigest ? { final_git_metadata_digest: finalGitMetadataDigest } : {}),
139
+ ...(headAfter ? { head_after: headAfter } : {}),
140
+ ...(gitStatus !== null ? { git_dirty: Boolean(gitStatus) } : {}),
141
+ finalized_at: new Date().toISOString(),
142
+ };
143
+ if (recordPath)
144
+ await atomicWriteJSON(recordPath, retained);
145
+ return retained;
146
+ }
147
+ export async function markWorkspaceFinalizationFailed(workspace, { recordPath, warning } = {}) {
148
+ if (!workspace)
149
+ return null;
150
+ const terminal = {
151
+ ...workspace,
152
+ status: workspace.mode === "shared" ? "released" : "orphaned",
153
+ retained: workspace.mode !== "shared",
154
+ changed: null,
155
+ warning: warning || {
156
+ code: "workspace_finalization_failed",
157
+ message: "workspace finalization failed",
158
+ },
159
+ finalized_at: new Date().toISOString(),
160
+ };
161
+ if (recordPath)
162
+ await atomicWriteJSON(recordPath, terminal);
163
+ return terminal;
164
+ }
165
+ export async function cancelPlannedWorkspace({ root, runId }) {
166
+ return abandonPlannedWorkspace({ root, runId, status: "cancelled" });
167
+ }
168
+ export async function abandonPlannedWorkspace({ root, runId, status = "unused" }) {
169
+ const recordPath = workspaceRecordPath(root, runId);
170
+ const workspace = await readJSON(recordPath, null);
171
+ if (!workspace || workspace.status !== "planned")
172
+ return workspace;
173
+ const completed = { ...workspace, status, completed_at: new Date().toISOString() };
174
+ await atomicWriteJSON(recordPath, completed);
175
+ return completed;
176
+ }
177
+ export async function recoverInterruptedWorkspace({ root, runId }) {
178
+ const recordPath = workspaceRecordPath(root, runId);
179
+ const workspace = await readJSON(recordPath, null);
180
+ if (!workspace)
181
+ return null;
182
+ if (workspace.status === "provisioning") {
183
+ await cleanupProvisioning(workspace).catch(() => { });
184
+ const failed = {
185
+ ...workspace,
186
+ status: "failed",
187
+ retained: false,
188
+ error: { code: "daemon_restarted", message: "daemon stopped while provisioning the workspace" },
189
+ completed_at: new Date().toISOString(),
190
+ };
191
+ await atomicWriteJSON(recordPath, failed);
192
+ return failed;
193
+ }
194
+ if (["ready", "running"].includes(workspace.status)) {
195
+ const orphaned = {
196
+ ...workspace,
197
+ status: workspace.mode === "shared" ? "released" : "orphaned",
198
+ retained: workspace.mode !== "shared",
199
+ completed_at: new Date().toISOString(),
200
+ };
201
+ await atomicWriteJSON(recordPath, orphaned);
202
+ return orphaned;
203
+ }
204
+ if (workspace.status === "planned")
205
+ return cancelPlannedWorkspace({ root, runId });
206
+ return workspace;
207
+ }
208
+ export async function inspectWorkspace({ root, runId }) {
209
+ assertRunId(runId);
210
+ return readJSON(workspaceRecordPath(root, runId), null);
211
+ }
212
+ export async function removeWorkspace({ root, runId, force = false }) {
213
+ assertRunId(runId);
214
+ const recordPath = workspaceRecordPath(root, runId);
215
+ const workspace = await readJSON(recordPath, null);
216
+ if (!workspace) {
217
+ throw new HitchError(`workspace record not found: ${runId}`, { code: "workspace_not_found", exitCode: 3 });
218
+ }
219
+ if (workspace.mode === "shared") {
220
+ throw invalidInput(`run ${runId} used a shared workspace that Hitch does not own`);
221
+ }
222
+ if (ACTIVE_WORKSPACE_STATES.has(workspace.status)) {
223
+ throw new HitchError(`workspace is still in use by ${runId}`, { code: "workspace_in_use", exitCode: 11 });
224
+ }
225
+ if (!force && workspace.changed !== false) {
226
+ throw new HitchError("workspace may contain changes; pass --force to remove it", {
227
+ code: "workspace_has_changes",
228
+ exitCode: 11,
229
+ });
230
+ }
231
+ const expectedDirectory = path.join(await canonicalizePotentialPath(statePaths(root).workspaces), runId);
232
+ const expectedExecutionRoot = path.join(expectedDirectory, "root");
233
+ const recordedDirectory = workspace.managed_directory
234
+ ? await canonicalizePotentialPath(workspace.managed_directory)
235
+ : null;
236
+ const recordedExecutionRoot = workspace.execution_root
237
+ ? await canonicalizePotentialPath(workspace.execution_root)
238
+ : null;
239
+ if (!recordedDirectory
240
+ || !recordedExecutionRoot
241
+ || path.resolve(recordedDirectory) !== path.resolve(expectedDirectory)
242
+ || path.resolve(recordedExecutionRoot) !== path.resolve(expectedExecutionRoot)) {
243
+ throw new HitchError("workspace record points outside the managed workspace root", {
244
+ code: "workspace_cleanup_rejected",
245
+ exitCode: 11,
246
+ });
247
+ }
248
+ if (workspace.mode === "worktree" && workspace.git?.common_dir) {
249
+ const git = workspace.git;
250
+ await withWorkspaceLock(root, git.common_dir, async () => {
251
+ if (await pathExists(git.common_dir) && await registeredWorktree(git.common_dir, workspace.execution_root)) {
252
+ await runGit(["--git-dir", git.common_dir, "worktree", "remove", "--force", workspace.execution_root], {
253
+ failureCode: "workspace_cleanup_failed",
254
+ failureExitCode: 12,
255
+ });
256
+ }
257
+ });
258
+ }
259
+ await rm(expectedDirectory, { recursive: true, force: true });
260
+ const removed = {
261
+ ...workspace,
262
+ status: "removed",
263
+ retained: false,
264
+ removed_at: new Date().toISOString(),
265
+ };
266
+ await atomicWriteJSON(recordPath, removed);
267
+ return removed;
268
+ }
269
+ async function cleanupProvisioning(workspace) {
270
+ await assertManagedPlan(workspace);
271
+ const git = workspace.git;
272
+ if (workspace.mode === "worktree"
273
+ && git?.common_dir
274
+ && await pathExists(git.common_dir)
275
+ && await registeredWorktree(git.common_dir, workspace.execution_root)) {
276
+ await withWorkspaceLock(workspace.state_root, git.common_dir, () => runGit([
277
+ "--git-dir",
278
+ git.common_dir,
279
+ "worktree",
280
+ "remove",
281
+ "--force",
282
+ workspace.execution_root,
283
+ ], {
284
+ failureCode: "workspace_cleanup_failed",
285
+ failureExitCode: 12,
286
+ })).catch(() => { });
287
+ }
288
+ if (workspace.managed_directory)
289
+ await rm(workspace.managed_directory, { recursive: true, force: true });
290
+ }
291
+ async function assertManagedPlan(workspace) {
292
+ assertRunId(workspace.run_id);
293
+ if (!workspace.state_root) {
294
+ throw new HitchError("workspace plan is missing its state root", {
295
+ code: "workspace_cleanup_rejected",
296
+ exitCode: 11,
297
+ });
298
+ }
299
+ const expectedDirectory = path.join(await canonicalizePotentialPath(statePaths(workspace.state_root).workspaces), workspace.run_id);
300
+ const expectedRoot = path.join(expectedDirectory, "root");
301
+ if (path.resolve(workspace.managed_directory || "") !== path.resolve(expectedDirectory)
302
+ || path.resolve(workspace.execution_root || "") !== path.resolve(expectedRoot)
303
+ || !isWithin(expectedRoot, path.resolve(workspace.execution_workspace || ""))) {
304
+ throw new HitchError("workspace plan points outside the managed workspace root", {
305
+ code: "workspace_cleanup_rejected",
306
+ exitCode: 11,
307
+ });
308
+ }
309
+ }
310
+ function gitMetadataExclusion(workspace) {
311
+ return workspace.git ? new Set([".git"]) : new Set();
312
+ }
313
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/workspaces/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { realpath, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { HitchError, SCHEMA_VERSION, atomicWriteJSON, invalidInput, statePaths } from "../foundation/index.js";
4
+ import { inspectGitWorkspace } from "./git.js";
5
+ import { WORKSPACE_MODES } from "./types.js";
6
+ import { assertNoWorkspaceOverlap, assertRunId, canonicalizePotentialPath, isWithin } from "./utils.js";
7
+ export async function planWorkspace({ runId, sourceCwd, mode = "shared", root, recordPath }) {
8
+ assertRunId(runId);
9
+ if (!WORKSPACE_MODES.has(mode)) {
10
+ throw invalidInput(`workspace_mode must be one of: ${[...WORKSPACE_MODES].join(", ")}`);
11
+ }
12
+ let sourceRealPath;
13
+ let sourceInfo;
14
+ try {
15
+ sourceRealPath = await realpath(sourceCwd);
16
+ sourceInfo = await stat(sourceRealPath);
17
+ }
18
+ catch (error) {
19
+ throw invalidInput(`workspace does not exist: ${sourceCwd}`, { cause: error });
20
+ }
21
+ if (!sourceInfo.isDirectory())
22
+ throw invalidInput(`workspace is not a directory: ${sourceCwd}`);
23
+ const paths = statePaths(root);
24
+ const managedDirectory = path.join(await canonicalizePotentialPath(paths.workspaces), runId);
25
+ let git = null;
26
+ let sourceBase = sourceRealPath;
27
+ let sourceSubdirectory = ".";
28
+ if (mode !== "shared") {
29
+ git = await inspectGitWorkspace(sourceRealPath, { required: mode === "worktree" });
30
+ if (git) {
31
+ sourceBase = git.repository_root;
32
+ sourceSubdirectory = path.relative(sourceBase, sourceRealPath) || ".";
33
+ }
34
+ const stateRoot = await canonicalizePotentialPath(paths.root);
35
+ if (isWithin(sourceBase, stateRoot)) {
36
+ throw new HitchError("the Hitch state root is inside the source workspace; use a --root outside the source repository", { code: "workspace_root_overlap", exitCode: 2 });
37
+ }
38
+ assertNoWorkspaceOverlap(sourceBase, managedDirectory);
39
+ }
40
+ if (mode === "worktree") {
41
+ if (git?.status) {
42
+ throw new HitchError("worktree isolation requires a clean Git workspace; use workspace_mode=copy to preserve local changes", { code: "workspace_dirty", exitCode: 2 });
43
+ }
44
+ }
45
+ const executionRoot = mode === "shared" ? sourceRealPath : path.join(managedDirectory, "root");
46
+ const executionWorkspace = sourceSubdirectory === "."
47
+ ? executionRoot
48
+ : path.join(executionRoot, sourceSubdirectory);
49
+ const snapshot = mode === "worktree"
50
+ ? { consistency: "git_commit", ...(git?.head ? { commit: git.head } : {}), source_subdirectory: sourceSubdirectory }
51
+ : mode === "copy"
52
+ ? {
53
+ consistency: "best_effort",
54
+ ...(git?.head ? { commit: git.head } : {}),
55
+ source_subdirectory: sourceSubdirectory,
56
+ }
57
+ : { consistency: "none", source_subdirectory: "." };
58
+ const plan = {
59
+ schema_version: SCHEMA_VERSION,
60
+ run_id: runId,
61
+ state_root: path.resolve(root),
62
+ mode: mode,
63
+ status: "planned",
64
+ source_workspace: path.resolve(sourceCwd),
65
+ source_realpath: sourceRealPath,
66
+ source_base: sourceBase,
67
+ source_subdirectory: sourceSubdirectory,
68
+ execution_root: executionRoot,
69
+ execution_workspace: executionWorkspace,
70
+ managed_directory: mode === "shared" ? null : managedDirectory,
71
+ snapshot,
72
+ git,
73
+ retained: false,
74
+ planned_at: new Date().toISOString(),
75
+ };
76
+ if (recordPath)
77
+ await atomicWriteJSON(recordPath, plan);
78
+ return plan;
79
+ }
80
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../../src/workspaces/planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { sha256Bytes, statePaths, withFileLock } from "../foundation/index.js";
2
+ import path from "node:path";
3
+ export function workspaceRecordPath(root, runId) {
4
+ return path.join(statePaths(root).runs, runId, "workspace.json");
5
+ }
6
+ export function workspaceManifestFields(workspace) {
7
+ if (!workspace)
8
+ return {};
9
+ return {
10
+ workspace_mode: workspace.mode,
11
+ source_workspace: workspace.source_workspace,
12
+ execution_workspace: workspace.execution_workspace,
13
+ workspace_snapshot: workspace.snapshot,
14
+ workspace_retained: Boolean(workspace.retained),
15
+ ...(workspace.changed !== undefined ? { workspace_changed: workspace.changed } : {}),
16
+ };
17
+ }
18
+ export async function withWorkspaceLock(root, identity, operation, { signal } = {}) {
19
+ return withFileLock(statePaths(root).workspaceLocks, sha256Bytes(identity), operation, {
20
+ timeoutCode: "workspace_locked",
21
+ timeoutExitCode: 5,
22
+ ...(signal ? { signal } : {}),
23
+ });
24
+ }
25
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/workspaces/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE/E,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,KAAY;IAC5D,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,SAA2C;IACjF,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAC1B,OAAO;QACL,cAAc,EAAE,SAAS,CAAC,IAAI;QAC9B,gBAAgB,EAAE,SAAS,CAAC,gBAAgB;QAC5C,mBAAmB,EAAE,SAAS,CAAC,mBAAmB;QAClD,kBAAkB,EAAE,SAAS,CAAC,QAAQ;QACtC,kBAAkB,EAAE,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC;QAC/C,GAAG,CAAC,SAAS,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAI,IAAY,EAAE,QAAgB,EAAE,SAA2B,EAAE,EAAE,MAAM,KAA2C,EAAE;IAC3J,OAAO,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE;QACrF,WAAW,EAAE,kBAAkB;QAC/B,eAAe,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ export const WORKSPACE_MODES = new Set(["shared", "worktree", "copy"]);
2
+ export const COMMAND_TIMEOUT_MS = 120_000;
3
+ export const ACTIVE_WORKSPACE_STATES = new Set(["planned", "provisioning", "ready", "running"]);
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/workspaces/types.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAC1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { lstat, realpath } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { HitchError, invalidInput } from "../foundation/index.js";
4
+ export function assertNoWorkspaceOverlap(source, managedDirectory) {
5
+ const sourcePath = path.resolve(source);
6
+ const managedPath = path.resolve(managedDirectory);
7
+ if (isWithin(sourcePath, managedPath) || isWithin(managedPath, sourcePath)) {
8
+ throw new HitchError("managed workspace storage overlaps the source workspace; use a Hitch --root outside the source repository", { code: "workspace_root_overlap", exitCode: 2 });
9
+ }
10
+ }
11
+ export function isWithin(parent, candidate) {
12
+ const relative = path.relative(parent, candidate);
13
+ return relative === "" || (!relative.startsWith(`..${path.sep}`) && relative !== "..");
14
+ }
15
+ export async function pathExists(file) {
16
+ try {
17
+ await lstat(file);
18
+ return true;
19
+ }
20
+ catch (error) {
21
+ if (error?.code === "ENOENT")
22
+ return false;
23
+ throw error;
24
+ }
25
+ }
26
+ export async function canonicalizePotentialPath(file) {
27
+ const missing = [];
28
+ let current = path.resolve(file);
29
+ for (;;) {
30
+ try {
31
+ const resolved = await realpath(current);
32
+ return path.join(resolved, ...missing.reverse());
33
+ }
34
+ catch (error) {
35
+ if (error?.code !== "ENOENT")
36
+ throw error;
37
+ const parent = path.dirname(current);
38
+ if (parent === current)
39
+ throw error;
40
+ missing.push(path.basename(current));
41
+ current = parent;
42
+ }
43
+ }
44
+ }
45
+ export function assertRunId(runId) {
46
+ if (!/^run_[a-f0-9]{32}$/.test(runId || ""))
47
+ throw invalidInput(`invalid run ID: ${runId || ""}`);
48
+ }
49
+ export function throwIfAborted(signal) {
50
+ if (signal?.aborted)
51
+ throw cancelledError();
52
+ }
53
+ export function cancelledError() {
54
+ return new HitchError("workspace preparation cancelled", { code: "cancelled", exitCode: 9 });
55
+ }
56
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/workspaces/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,UAAU,wBAAwB,CAAC,MAAc,EAAE,gBAAwB;IAC/E,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnD,IAAI,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,UAAU,CAClB,2GAA2G,EAC3G,EAAE,IAAI,EAAE,wBAAwB,EAAE,QAAQ,EAAE,CAAC,EAAE,CAChD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,SAAiB;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClD,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QAClB,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,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,IAAY;IAC1D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,SAAS,CAAC;QACR,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,EAAE,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;YACrE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACrC,IAAI,MAAM,KAAK,OAAO;gBAAE,MAAM,KAAK,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YACrC,OAAO,GAAG,MAAM,CAAC;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAAE,MAAM,YAAY,CAAC,mBAAmB,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAA+B;IAC5D,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,cAAc,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,UAAU,CAAC,iCAAiC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;AAC/F,CAAC"}
@@ -9,6 +9,8 @@
9
9
  "schema_version": { "const": "1" },
10
10
  "backend": { "const": "harbor" },
11
11
  "dataset": { "type": "string", "minLength": 1 },
12
+ "benchmark_id": { "type": "string", "minLength": 1 },
13
+ "benchmark_revision": { "type": "string", "minLength": 1 },
12
14
  "harness_ref": { "type": "string", "minLength": 1 },
13
15
  "model": { "type": "string" },
14
16
  "attempts": { "type": "integer", "minimum": 1 },
@@ -4,7 +4,7 @@
4
4
  "title": "Hitch eval result",
5
5
  "type": "object",
6
6
  "additionalProperties": true,
7
- "required": ["schema_version", "eval_id", "status", "exit_code", "started_at", "completed_at"],
7
+ "required": ["schema_version", "eval_id", "benchmark_id", "benchmark_revision", "status", "exit_code", "trials", "started_at", "completed_at"],
8
8
  "properties": {
9
9
  "schema_version": { "const": "1" },
10
10
  "eval_id": { "type": "string", "pattern": "^eval_[a-f0-9]{32}$" },
@@ -25,6 +25,41 @@
25
25
  "additionalProperties": true
26
26
  },
27
27
  "summary": { "type": ["object", "null"] },
28
+ "benchmark_id": { "type": "string", "minLength": 1 },
29
+ "benchmark_revision": { "type": "string", "minLength": 1 },
30
+ "trials": {
31
+ "type": "array",
32
+ "items": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["trial_id", "run_id", "task_id", "attempt", "observation_status"],
36
+ "properties": {
37
+ "trial_id": { "type": "string", "minLength": 1 },
38
+ "run_id": { "type": "string", "pattern": "^run_[a-f0-9]{32}$" },
39
+ "task_id": { "type": "string", "minLength": 1 },
40
+ "attempt": { "type": "integer", "minimum": 1 },
41
+ "observation_status": { "enum": ["valid", "invalid"] },
42
+ "reward": { "type": "number" },
43
+ "verifier_result_ref": { "type": "string", "minLength": 1 },
44
+ "invalid_reason": { "type": "string", "minLength": 1 }
45
+ }
46
+ }
47
+ },
48
+ "local_source_transport": {
49
+ "type": "object",
50
+ "required": ["kind", "resolution_identity", "commit", "tree", "payload_sha256", "payload_bytes"],
51
+ "properties": {
52
+ "kind": { "const": "local-git-commit" },
53
+ "resolution_identity": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
54
+ "commit": { "type": "string", "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$" },
55
+ "tree": { "type": "string", "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$" },
56
+ "payload_sha256": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
57
+ "payload_bytes": { "type": "integer", "minimum": 0 },
58
+ "object_count": { "type": "integer", "minimum": 0 },
59
+ "file_count": { "type": "integer", "minimum": 0 }
60
+ },
61
+ "additionalProperties": false
62
+ },
28
63
  "error": {
29
64
  "type": "object",
30
65
  "required": ["code", "message"],
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://agent-hitch.local/schemas/local-git-transport-manifest.schema.json",
4
+ "title": "Hitch local Git commit transport manifest",
5
+ "description": "Proof for a size-limited Git object pack containing one exact local commit and its checkout tree. The Git commit remains the harness revision identity; payload_sha256 only proves transport integrity.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schema_version",
10
+ "kind",
11
+ "harness_id",
12
+ "resolution_identity",
13
+ "commit",
14
+ "tree",
15
+ "payload_sha256",
16
+ "payload_bytes",
17
+ "object_count",
18
+ "file_count",
19
+ "created_at"
20
+ ],
21
+ "properties": {
22
+ "schema_version": { "const": "1" },
23
+ "kind": { "const": "local-git-commit" },
24
+ "harness_id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
25
+ "resolution_identity": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
26
+ "commit": { "type": "string", "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$" },
27
+ "tree": { "type": "string", "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$" },
28
+ "payload_sha256": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
29
+ "payload_bytes": { "type": "integer", "minimum": 0 },
30
+ "object_count": { "type": "integer", "minimum": 0 },
31
+ "file_count": { "type": "integer", "minimum": 0 },
32
+ "created_at": { "type": "string", "format": "date-time" }
33
+ }
34
+ }