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,314 @@
1
+ /**
2
+ * DSH-compatible message feedback sidecar (spec §6).
3
+ *
4
+ * One whole-session row bound to `{ sessionId, createdAt, cwd }`, stored as an
5
+ * atomic whole-row replacement. A lifecycle identity mismatch is treated as
6
+ * absence, preventing a reused session id from inheriting stale feedback.
7
+ * Forked sessions do not inherit feedback. Compare-and-set uses opaque opaque
8
+ * UUID versions; `ifVersion: null` requests creation only.
9
+ */
10
+ import { randomUUID } from "node:crypto";
11
+ import path from "node:path";
12
+ import { atomicWriteJSON, ensureDir, readJSON } from "../foundation/index.js";
13
+ import { validateMessageFeedbackRow } from "../domain/index.js";
14
+ import { decodeSegment, encodeSegment, loadTrajectoryRef, readTrajectory, sessionDir } from "../trajectories/index.js";
15
+ import { readFile, readdir } from "node:fs/promises";
16
+ export class MessageFeedbackError extends Error {
17
+ code;
18
+ current;
19
+ maxBytes;
20
+ actualBytes;
21
+ constructor(code, message, extra = {}) {
22
+ super(message);
23
+ this.name = "MessageFeedbackError";
24
+ this.code = code;
25
+ if (extra.current !== undefined)
26
+ this.current = extra.current;
27
+ if (extra.maxBytes !== undefined)
28
+ this.maxBytes = extra.maxBytes;
29
+ if (extra.actualBytes !== undefined)
30
+ this.actualBytes = extra.actualBytes;
31
+ }
32
+ }
33
+ /**
34
+ * Infrastructure error for sidecar storage corruption or I/O failures. Unlike
35
+ * the business failure variants, this is not a `MessageFeedbackError` and must
36
+ * not be reported as one (spec §6.3).
37
+ */
38
+ export class FeedbackStorageError extends Error {
39
+ constructor(message) {
40
+ super(message);
41
+ this.name = "FeedbackStorageError";
42
+ }
43
+ }
44
+ export const DEFAULT_MAX_NOTE_BYTES = 8192;
45
+ /**
46
+ * The sidecar service. The session identity must be supplied by the caller
47
+ * (Hitch run records know `createdAt`/`cwd`); a row whose stored identity
48
+ * differs is treated as absent.
49
+ */
50
+ export class MessageFeedbackService {
51
+ root;
52
+ maxNoteBytes;
53
+ validateTarget;
54
+ queues = new Map();
55
+ constructor({ root, maxNoteBytes = DEFAULT_MAX_NOTE_BYTES, validateTarget }) {
56
+ this.root = root;
57
+ this.maxNoteBytes = maxNoteBytes;
58
+ this.validateTarget = validateTarget;
59
+ }
60
+ rowPath(sessionId) {
61
+ return path.join(this.root, "feedback", "message-feedback.json");
62
+ }
63
+ serialize(sessionId, operation) {
64
+ const previous = this.queues.get(sessionId) || Promise.resolve();
65
+ const next = previous.then(operation, operation);
66
+ this.queues.set(sessionId, next.catch(() => { }));
67
+ return next;
68
+ }
69
+ async list(request, identity) {
70
+ return this.serialize(request.sessionId, async () => {
71
+ const row = await this.readRow(request.sessionId, identity);
72
+ return row ? [...row.items] : [];
73
+ });
74
+ }
75
+ async put(request, identity, target) {
76
+ validateNote(request.note, this.maxNoteBytes);
77
+ return this.serialize(request.sessionId, async () => {
78
+ if (this.validateTarget && !await this.validateTarget(request.sessionId, target.messageId)) {
79
+ throw new MessageFeedbackError("target-not-found", "no append-origin assistant message matches the requested messageId");
80
+ }
81
+ const row = await this.readRow(request.sessionId, identity);
82
+ const now = Date.now();
83
+ const existingIndex = row ? row.items.findIndex((item) => item.messageId === target.messageId) : -1;
84
+ const existing = existingIndex >= 0 && row ? row.items[existingIndex] : undefined;
85
+ if (request.ifVersion === null) {
86
+ if (existing)
87
+ throw versionConflict(existing);
88
+ const created = {
89
+ messageId: target.messageId,
90
+ rating: request.rating,
91
+ version: randomUUID(),
92
+ createdAt: now,
93
+ updatedAt: now,
94
+ };
95
+ if (request.note !== undefined)
96
+ created.note = request.note;
97
+ const nextRow = row
98
+ ? { ...row, items: [...row.items, created] }
99
+ : { session: identitySession(identity), items: [created] };
100
+ await this.writeRow(request.sessionId, nextRow);
101
+ return created;
102
+ }
103
+ if (!existing)
104
+ throw versionConflict(null);
105
+ if (existing.version !== request.ifVersion)
106
+ throw versionConflict(existing);
107
+ const desiredNote = request.note;
108
+ const unchanged = existing.rating === request.rating
109
+ && existing.note === desiredNote
110
+ && existing.version === request.ifVersion;
111
+ if (unchanged)
112
+ return existing;
113
+ const updated = {
114
+ messageId: existing.messageId,
115
+ rating: request.rating,
116
+ version: randomUUID(),
117
+ createdAt: existing.createdAt,
118
+ updatedAt: Math.max(now, existing.updatedAt),
119
+ };
120
+ if (desiredNote !== undefined)
121
+ updated.note = desiredNote;
122
+ const items = [...(row?.items || [])];
123
+ items[existingIndex] = updated;
124
+ const nextRow = {
125
+ session: row?.session || identitySession(identity),
126
+ items,
127
+ };
128
+ await this.writeRow(request.sessionId, nextRow);
129
+ return updated;
130
+ });
131
+ }
132
+ async delete(request, identity) {
133
+ return this.serialize(request.sessionId, async () => {
134
+ const row = await this.readRow(request.sessionId, identity);
135
+ if (!row)
136
+ return { absent: true };
137
+ const existingIndex = row.items.findIndex((item) => item.messageId === request.messageId);
138
+ if (existingIndex < 0)
139
+ return { absent: true };
140
+ const existing = row.items[existingIndex];
141
+ // Delete ignores the supplied version only when the item is already
142
+ // absent; an existing item requires its exact current version even when
143
+ // `ifVersion` is null (spec §6.2). A null ifVersion therefore cannot
144
+ // delete an existing item.
145
+ if (existing && existing.version !== request.ifVersion) {
146
+ throw versionConflict(existing);
147
+ }
148
+ const items = row.items.filter((item) => item.messageId !== request.messageId);
149
+ await this.writeRow(request.sessionId, { ...row, items });
150
+ return { absent: true };
151
+ });
152
+ }
153
+ async readRow(sessionId, identity) {
154
+ const raw = await readJSON(this.rowPath(sessionId), null);
155
+ if (raw === null)
156
+ return null;
157
+ let row;
158
+ try {
159
+ row = validateMessageFeedbackRow(raw);
160
+ }
161
+ catch {
162
+ // Storage corruption and I/O failures are infrastructure errors, not
163
+ // business failure variants (spec §6.3): a corrupt row must never be
164
+ // misreported as session-not-found.
165
+ throw new FeedbackStorageError("message feedback sidecar is corrupt");
166
+ }
167
+ if (!sameIdentity(row.session, identity))
168
+ return null;
169
+ return row;
170
+ }
171
+ async writeRow(sessionId, row) {
172
+ const file = this.rowPath(sessionId);
173
+ await ensureDir(path.dirname(file));
174
+ await atomicWriteJSON(file, row);
175
+ }
176
+ }
177
+ function identitySession(identity) {
178
+ const session = {
179
+ sessionId: identity.sessionId,
180
+ createdAt: identity.createdAt,
181
+ };
182
+ if (identity.cwd !== undefined)
183
+ session.cwd = identity.cwd;
184
+ return session;
185
+ }
186
+ function sameIdentity(stored, expected) {
187
+ if (stored.sessionId !== undefined && stored.sessionId !== expected.sessionId)
188
+ return false;
189
+ if (stored.createdAt !== expected.createdAt)
190
+ return false;
191
+ if ((stored.cwd ?? undefined) !== (expected.cwd ?? undefined))
192
+ return false;
193
+ return true;
194
+ }
195
+ function validateNote(note, maxNoteBytes) {
196
+ if (note === undefined)
197
+ return;
198
+ if (!/\S/.test(note)) {
199
+ throw new MessageFeedbackError("note-blank", "note must contain a non-whitespace character");
200
+ }
201
+ const bytes = Buffer.byteLength(note, "utf8");
202
+ if (bytes > maxNoteBytes) {
203
+ throw new MessageFeedbackError("note-too-large", `note exceeds ${maxNoteBytes} UTF-8 bytes`, {
204
+ maxBytes: maxNoteBytes,
205
+ actualBytes: bytes,
206
+ });
207
+ }
208
+ }
209
+ function versionConflict(current) {
210
+ return new MessageFeedbackError("version-conflict", "message feedback version conflict", { current });
211
+ }
212
+ /**
213
+ * Resolve a run directory's canonical trajectory for feedback targeting.
214
+ * Returns `null` when the run has no trajectory ref (legacy event-log runs
215
+ * are not feedback targets).
216
+ */
217
+ export async function resolveFeedbackSession(runDirectory) {
218
+ const ref = await loadTrajectoryRef(runDirectory);
219
+ if (!ref)
220
+ return null;
221
+ const header = await readTrajectoryHeader(ref.path);
222
+ if (!header)
223
+ return null;
224
+ return {
225
+ sessionId: ref.session_id,
226
+ createdAt: header.createdAt,
227
+ ...(header.cwd !== undefined ? { cwd: header.cwd } : {}),
228
+ };
229
+ }
230
+ async function readTrajectoryHeader(file) {
231
+ try {
232
+ const content = await readFile(file, "utf8");
233
+ const first = content.split(/\r?\n/).find((line) => line.length > 0);
234
+ if (!first)
235
+ return null;
236
+ const parsed = JSON.parse(first);
237
+ if (typeof parsed.createdAt !== "number")
238
+ return null;
239
+ const result = { createdAt: parsed.createdAt };
240
+ if (typeof parsed.cwd === "string")
241
+ result.cwd = parsed.cwd;
242
+ return result;
243
+ }
244
+ catch {
245
+ return null;
246
+ }
247
+ }
248
+ /**
249
+ * Validate that a messageId targets a non-empty, append-origin
250
+ * `assistant/message` in the run's canonical trajectory (spec §6.2).
251
+ */
252
+ export async function trajectoryTargetValidator(runDirectory) {
253
+ return async (_sessionId, messageId) => {
254
+ const ref = await loadTrajectoryRef(runDirectory);
255
+ if (!ref)
256
+ return false;
257
+ try {
258
+ const { events } = await readTrajectory(ref.path);
259
+ return events.some((event) => {
260
+ if (event.type !== "assistant/message" || event.surfaceOp !== "append")
261
+ return false;
262
+ const data = (event.data || {});
263
+ const message = (data.message || {});
264
+ if (message.id !== messageId)
265
+ return false;
266
+ const content = Array.isArray(message.content) ? message.content : [];
267
+ const text = content.find((block) => block.type === "text")?.text;
268
+ return typeof text === "string" && text.length > 0;
269
+ });
270
+ }
271
+ catch {
272
+ return false;
273
+ }
274
+ };
275
+ }
276
+ /**
277
+ * Locate the canonical trajectory session.jsonl path for a session id under a
278
+ * run directory, scanning encoded session directories (used by the feedback
279
+ * CLI when only the session id is known).
280
+ */
281
+ export async function findTrajectorySessionFile(runDirectory, sessionId) {
282
+ const ref = await loadTrajectoryRef(runDirectory);
283
+ if (ref)
284
+ return ref.path;
285
+ const root = path.join(runDirectory, "trajectory");
286
+ let projects;
287
+ try {
288
+ projects = await readdir(root, { withFileTypes: true });
289
+ }
290
+ catch {
291
+ return null;
292
+ }
293
+ const encoded = encodeSegment(sessionId);
294
+ for (const project of projects) {
295
+ if (!project.isDirectory())
296
+ continue;
297
+ const candidate = path.join(root, project.name, encoded, "session.jsonl");
298
+ try {
299
+ const content = await readFile(candidate, "utf8");
300
+ const first = content.split(/\r?\n/).find((line) => line.length > 0);
301
+ if (!first)
302
+ continue;
303
+ const parsed = JSON.parse(first);
304
+ if (parsed.id === sessionId || decodeSegment(encoded) === sessionId)
305
+ return candidate;
306
+ }
307
+ catch {
308
+ // Not this project.
309
+ }
310
+ }
311
+ return null;
312
+ }
313
+ export { sameIdentity, sessionDir };
314
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/feedback/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { homedir } from "node:os";
2
+ import path from "node:path";
3
+ import { invalidInput } from "./errors.js";
4
+ export const SCHEMA_VERSION = "1";
5
+ export const DEFAULT_PORT = 7463;
6
+ export const DEFAULT_MAX_CONCURRENT = 4;
7
+ export function defaultRoot() {
8
+ return path.resolve(process.env.HITCH_ROOT || path.join(homedir(), ".hitch"));
9
+ }
10
+ export function parseDuration(value) {
11
+ if (value === undefined || value === null || value === "")
12
+ return 0;
13
+ if (typeof value === "number" && Number.isFinite(value))
14
+ return value;
15
+ const match = String(value).trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/);
16
+ if (!match)
17
+ throw invalidInput(`invalid duration: ${value}`);
18
+ const scale = { ms: 1, s: 1_000, m: 60_000, h: 3_600_000 };
19
+ const unit = match[2] || "ms";
20
+ return Math.round(Number(match[1]) * (scale[unit] ?? 1));
21
+ }
22
+ export function positiveInteger(value, name) {
23
+ const number = Number(value);
24
+ if (!Number.isInteger(number) || number <= 0) {
25
+ throw invalidInput(`${name} must be a positive integer`);
26
+ }
27
+ return number;
28
+ }
29
+ export function statePaths(root) {
30
+ return {
31
+ root,
32
+ daemon: path.join(root, "daemon.json"),
33
+ lock: path.join(root, "daemon.lock"),
34
+ token: path.join(root, "daemon.token"),
35
+ log: path.join(root, "daemon.log"),
36
+ errorLog: path.join(root, "daemon.err.log"),
37
+ runs: path.join(root, "runs"),
38
+ evals: path.join(root, "evals"),
39
+ tools: path.join(root, "tools"),
40
+ store: path.join(root, "store"),
41
+ artifacts: path.join(root, "store", "artifacts"),
42
+ artifactIndex: path.join(root, "store", "refs"),
43
+ sourceCache: path.join(root, "cache", "sources"),
44
+ artifactLocks: path.join(root, "locks", "artifacts"),
45
+ sourceLocks: path.join(root, "locks", "sources"),
46
+ workspaceLocks: path.join(root, "locks", "workspaces"),
47
+ controllerRuntimeLocks: path.join(root, "locks", "controller-runtimes"),
48
+ controllerRuntimes: path.join(root, "store", "controller-runtimes", "sha256"),
49
+ workspaces: path.join(root, "workspaces"),
50
+ temporary: path.join(root, "tmp"),
51
+ indexes: path.join(root, "indexes"),
52
+ };
53
+ }
54
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/foundation/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export class HitchError extends Error {
2
+ code;
3
+ exitCode;
4
+ constructor(message, { code = "internal_error", exitCode = 12, cause } = {}) {
5
+ super(message, cause === undefined ? undefined : { cause });
6
+ this.name = "HitchError";
7
+ this.code = code;
8
+ this.exitCode = exitCode;
9
+ }
10
+ }
11
+ export function invalidInput(message, { cause } = {}) {
12
+ return new HitchError(message, { code: "invalid_input", exitCode: 2, cause });
13
+ }
14
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/foundation/errors.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,IAAI,CAAS;IACb,QAAQ,CAAS;IAE1B,YAAY,OAAe,EAAE,EAAE,IAAI,GAAG,gBAAgB,EAAE,QAAQ,GAAG,EAAE,EAAE,KAAK,KAAwB,EAAE;QACpG,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,EAAE,KAAK,KAA0B,EAAE;IAC/E,OAAO,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,135 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { constants, createReadStream } from "node:fs";
4
+ import { access, lstat, realpath } from "node:fs/promises";
5
+ import path, { delimiter, isAbsolute, join, resolve } from "node:path";
6
+ import { HitchError } from "./errors.js";
7
+ import { terminateProcess } from "./process.js";
8
+ export function runCommand(executable, args, { cwd, env = process.env, failureCode = "internal_error", failureExitCode = 12, timeoutMs = 30 * 60 * 1_000, signal, } = {}) {
9
+ throwIfAborted(signal);
10
+ return new Promise((resolve, reject) => {
11
+ const child = spawn(executable, args, {
12
+ cwd,
13
+ env,
14
+ stdio: ["ignore", "pipe", "pipe"],
15
+ windowsHide: true,
16
+ detached: process.platform !== "win32",
17
+ });
18
+ let stdout = "";
19
+ let stderr = "";
20
+ let aborted = false;
21
+ let settled = false;
22
+ const append = (current, chunk) => `${current}${chunk}`.slice(-1_000_000);
23
+ child.stdout.on("data", (chunk) => { stdout = append(stdout, chunk); });
24
+ child.stderr.on("data", (chunk) => { stderr = append(stderr, chunk); });
25
+ const timer = setTimeout(() => terminateProcess(child).catch(() => { }), timeoutMs);
26
+ timer.unref?.();
27
+ const finish = (callback) => {
28
+ if (settled)
29
+ return;
30
+ settled = true;
31
+ clearTimeout(timer);
32
+ signal?.removeEventListener("abort", abortHandler);
33
+ callback();
34
+ };
35
+ const abortHandler = () => {
36
+ aborted = true;
37
+ terminateProcess(child).catch(() => { });
38
+ };
39
+ signal?.addEventListener("abort", abortHandler, { once: true });
40
+ child.once("error", (error) => {
41
+ finish(() => reject(new HitchError(`failed to start ${path.basename(executable)}: ${error.message}`, {
42
+ code: failureCode,
43
+ exitCode: failureExitCode,
44
+ cause: error,
45
+ })));
46
+ });
47
+ child.once("close", (code, processSignal) => {
48
+ if (aborted)
49
+ return finish(() => reject(cancelledError()));
50
+ if (code === 0)
51
+ return finish(() => resolve({ stdout, stderr }));
52
+ const detail = stderr.trim() || stdout.trim();
53
+ finish(() => reject(new HitchError(`${path.basename(executable)} exited with code ${code ?? "null"}${processSignal ? ` (${processSignal})` : ""}${detail ? `: ${detail}` : ""}`, { code: failureCode, exitCode: failureExitCode })));
54
+ });
55
+ });
56
+ }
57
+ export function commandExecutable(command, env) {
58
+ const override = {
59
+ npm: "HITCH_NPM_PATH",
60
+ git: "HITCH_GIT_PATH",
61
+ cargo: "HITCH_CARGO_PATH",
62
+ bun: "HITCH_BUN_PATH",
63
+ pnpm: "HITCH_PNPM_PATH",
64
+ }[command];
65
+ return override && env[override]?.trim() ? env[override].trim() : command;
66
+ }
67
+ export async function commandVersion(executable, env, signal) {
68
+ try {
69
+ return (await runCommand(executable, ["--version"], { env, signal, timeoutMs: 5_000 })).stdout.trim() || "unknown";
70
+ }
71
+ catch (error) {
72
+ if (error?.code === "cancelled")
73
+ throw error;
74
+ return "unknown";
75
+ }
76
+ }
77
+ function throwIfAborted(signal) {
78
+ if (signal?.aborted)
79
+ throw cancelledError();
80
+ }
81
+ function cancelledError() {
82
+ return new HitchError("harness preparation cancelled", { code: "cancelled", exitCode: 9 });
83
+ }
84
+ export async function resolveExecutable(command, searchPath) {
85
+ const candidates = isAbsolute(command) || command.includes("/") || command.includes("\\")
86
+ ? [resolve(command)]
87
+ : searchPath.split(delimiter).filter(Boolean).map((directory) => join(directory, command));
88
+ for (const candidate of candidates) {
89
+ try {
90
+ await access(candidate, constants.X_OK);
91
+ const info = await lstat(candidate);
92
+ if (info.isDirectory())
93
+ continue;
94
+ return await realpath(candidate);
95
+ }
96
+ catch {
97
+ // Keep probing PATH entries.
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+ export async function detectVersion(executable, args, timeoutMs = 5_000) {
103
+ return new Promise((resolveVersion) => {
104
+ const child = spawn(executable, args, { stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
105
+ let stdout = "";
106
+ let stderr = "";
107
+ const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
108
+ child.stdout.on("data", (chunk) => { stdout += chunk; });
109
+ child.stderr.on("data", (chunk) => { stderr += chunk; });
110
+ child.once("error", () => {
111
+ clearTimeout(timer);
112
+ resolveVersion("");
113
+ });
114
+ child.once("close", () => {
115
+ clearTimeout(timer);
116
+ resolveVersion(selectVersionLine(stdout, stderr));
117
+ });
118
+ });
119
+ }
120
+ export async function fingerprintExecutable(executable) {
121
+ const hash = createHash("sha256");
122
+ for await (const chunk of createReadStream(executable))
123
+ hash.update(chunk);
124
+ return `sha256:${hash.digest("hex")}`;
125
+ }
126
+ export function selectVersionLine(stdout, stderr) {
127
+ const versionPattern = /(?:^|\s)v?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?(?:\s|$)/;
128
+ for (const stream of [stdout, stderr]) {
129
+ const match = String(stream || "").split(/\r?\n/).map((line) => line.trim()).find((line) => versionPattern.test(line));
130
+ if (match)
131
+ return match;
132
+ }
133
+ return "";
134
+ }
135
+ //# sourceMappingURL=executable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executable.js","sourceRoot":"","sources":["../../../src/foundation/executable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
2
+ import { randomBytes } from "node:crypto";
3
+ import path from "node:path";
4
+ export async function ensureDir(directory) {
5
+ await mkdir(directory, { recursive: true });
6
+ return directory;
7
+ }
8
+ /**
9
+ * Reads a JSON document. External JSON enters as `unknown`; callers narrow
10
+ * through runtime validators before use (spec §8.2).
11
+ */
12
+ export async function readJSON(file, fallback) {
13
+ try {
14
+ return JSON.parse(await readFile(file, "utf8"));
15
+ }
16
+ catch (error) {
17
+ if (error?.code === "ENOENT" && fallback !== undefined)
18
+ return fallback;
19
+ throw error;
20
+ }
21
+ }
22
+ export async function atomicWriteJSON(file, value, mode = 0o600) {
23
+ await ensureDir(path.dirname(file));
24
+ const temporary = `${file}.${process.pid}.${Date.now()}.${randomBytes(6).toString("hex")}.tmp`;
25
+ await writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`, { mode });
26
+ await rename(temporary, file);
27
+ }
28
+ export async function appendLine(file, value) {
29
+ await ensureDir(path.dirname(file));
30
+ const handle = await open(file, "a", 0o600);
31
+ try {
32
+ await handle.write(`${value}\n`);
33
+ }
34
+ finally {
35
+ await handle.close();
36
+ }
37
+ }
38
+ export async function removeIfExists(file) {
39
+ await rm(file, { force: true });
40
+ }
41
+ export async function writePrivateFile(file, value) {
42
+ await ensureDir(path.dirname(file));
43
+ await writeFile(file, value, { mode: 0o600 });
44
+ }
45
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../src/foundation/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB;IAC/C,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAc,IAAY,EAAE,QAAY;IACpE,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,EAAE,IAAI,KAAK,QAAQ,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,QAAQ,CAAC;QACnG,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,KAAc,EAAE,IAAI,GAAG,KAAK;IAC9E,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;IAC/F,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5E,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,KAAa;IAC1D,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;IACnC,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,KAAa;IAChE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { createHash } from "node:crypto";
2
+ export function canonicalJSON(value) {
3
+ if (Array.isArray(value))
4
+ return `[${value.map(canonicalJSON).join(",")}]`;
5
+ if (value && typeof value === "object") {
6
+ const record = value;
7
+ return `{${Object.keys(record)
8
+ .filter((key) => record[key] !== undefined)
9
+ .sort()
10
+ .map((key) => `${JSON.stringify(key)}:${canonicalJSON(record[key])}`)
11
+ .join(",")}}`;
12
+ }
13
+ return JSON.stringify(value);
14
+ }
15
+ export function sha256JSON(value) {
16
+ return `sha256:${createHash("sha256").update(canonicalJSON(value)).digest("hex")}`;
17
+ }
18
+ export function sha256Bytes(value) {
19
+ return `sha256:${createHash("sha256").update(value).digest("hex")}`;
20
+ }
21
+ export function digest(value) {
22
+ return sha256JSON(value);
23
+ }
24
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../../src/foundation/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC3E,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;aAC3B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;aAC1C,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;aACpE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAsB;IAChD,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,11 @@
1
+ export { DEFAULT_MAX_CONCURRENT, DEFAULT_PORT, SCHEMA_VERSION, defaultRoot, parseDuration, positiveInteger, statePaths } from "./config.js";
2
+ export { HitchError, invalidInput } from "./errors.js";
3
+ export { appendLine, atomicWriteJSON, ensureDir, readJSON, removeIfExists, writePrivateFile } from "./fs.js";
4
+ export { reclaimStaleLock } from "./locks.js";
5
+ export { withFileLock } from "./locks.js";
6
+ export { consumeLines } from "./line-stream.js";
7
+ export { packageRoot, packageVersion } from "./package-root.js";
8
+ export { delay, terminateProcess } from "./process.js";
9
+ export { commandExecutable, commandVersion, detectVersion, fingerprintExecutable, resolveExecutable, runCommand, selectVersionLine } from "./executable.js";
10
+ export { canonicalJSON, digest, sha256Bytes, sha256JSON } from "./hash.js";
11
+ //# sourceMappingURL=index.js.map