trellis 3.1.35 → 3.2.2

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 (287) hide show
  1. package/CHANGELOG.md +23 -5
  2. package/README.md +63 -156
  3. package/bin/trellis.mjs +2 -75
  4. package/dist/{better-sqlite-backend-ahx5p0br.js → better-sqlite-backend-2P4F6AOJ.js} +91 -29
  5. package/dist/boot-middleware-MHLHFCUC.js +9 -0
  6. package/dist/browser/index.d.ts +18 -0
  7. package/dist/browser/index.d.ts.map +1 -0
  8. package/dist/browser/index.js +95 -0
  9. package/dist/{index-53f3b8p8.js → chunk-2W3MHTMG.js} +552 -213
  10. package/dist/chunk-44FFQKQX.js +142 -0
  11. package/dist/chunk-4HYPLFJD.js +150 -0
  12. package/dist/chunk-4XIVMVHC.js +361 -0
  13. package/dist/{index-yp88he8n.js → chunk-6CTA6MCE.js} +88 -64
  14. package/dist/chunk-6GEZ6DN5.js +394 -0
  15. package/dist/chunk-7ZFRVCUE.js +211 -0
  16. package/dist/chunk-CAG4FULI.js +121 -0
  17. package/dist/chunk-FF36CQHZ.js +61 -0
  18. package/dist/{index-h32txmxe.js → chunk-FKQO5A3H.js} +6 -13
  19. package/dist/{index-nq520y6k.js → chunk-FWRS4CSC.js} +46 -32
  20. package/dist/chunk-GFZCJ4EH.js +108 -0
  21. package/dist/chunk-GLM4HGN4.js +55 -0
  22. package/dist/{index-4cdr7x2x.js → chunk-GU374KWZ.js} +182 -111
  23. package/dist/chunk-H6JB3PZ3.js +45 -0
  24. package/dist/chunk-IZX2PLIB.js +1240 -0
  25. package/dist/chunk-J2TXUFCZ.js +289 -0
  26. package/dist/chunk-J3WYZO3Q.js +211 -0
  27. package/dist/{index-xzym9w0m.js → chunk-JA7AIHRK.js} +12 -7
  28. package/dist/chunk-JHHEXEDM.js +162 -0
  29. package/dist/chunk-JUEMDWLU.js +233 -0
  30. package/dist/chunk-KFQGP6VL.js +33 -0
  31. package/dist/chunk-KIJITUZB.js +419 -0
  32. package/dist/{index-4wxa8xz4.js → chunk-KQ4A2D2P.js} +162 -23
  33. package/dist/chunk-KSU2GW22.js +958 -0
  34. package/dist/{index-rv1p47gp.js → chunk-L5N5PR2S.js} +3015 -2480
  35. package/dist/{index-h9e2efx4.js → chunk-LNUIGRDZ.js} +71 -55
  36. package/dist/{index-skhn0agf.js → chunk-MLC5BUYO.js} +19 -20
  37. package/dist/chunk-MPXUVGT3.js +104 -0
  38. package/dist/chunk-N6MYZT4O.js +68 -0
  39. package/dist/chunk-O2AV5WMN.js +48 -0
  40. package/dist/chunk-PZ4XYZ4J.js +143 -0
  41. package/dist/chunk-QB5ISE47.js +419 -0
  42. package/dist/chunk-RSWUFTO2.js +857 -0
  43. package/dist/chunk-S3XLFZ27.js +1095 -0
  44. package/dist/{index-w5wccer3.js → chunk-S6GBJ2ZB.js} +28 -12
  45. package/dist/{index-7pjz3tsy.js → chunk-SGMDTWJJ.js} +57 -15
  46. package/dist/chunk-SPSPV5BC.js +390 -0
  47. package/dist/chunk-TCKXSOBP.js +123 -0
  48. package/dist/chunk-UBGUDMUV.js +59 -0
  49. package/dist/{index-wt8rz4gn.js → chunk-UQISRW6T.js} +97 -26
  50. package/dist/chunk-USEINYUL.js +12 -0
  51. package/dist/{index-bmyt7k8n.js → chunk-UZRUP7QW.js} +12 -4
  52. package/dist/{index-xhcp6xrn.js → chunk-VBYUTRXX.js} +695 -514
  53. package/dist/{index-vkpkfwhq.js → chunk-VDAKEOML.js} +234 -194
  54. package/dist/chunk-WXSWA3MV.js +0 -0
  55. package/dist/{index-n9f2qyh5.js → chunk-X5FLTRUB.js} +55 -33
  56. package/dist/{index-h7zxhhhh.js → chunk-XMQ7G77X.js} +46 -38
  57. package/dist/{index-w7ng765c.js → chunk-YCM7ZYEZ.js} +102 -49
  58. package/dist/cli/deploy-cli.d.ts +18 -0
  59. package/dist/cli/deploy-cli.d.ts.map +1 -0
  60. package/dist/cli/errors.d.ts +6 -0
  61. package/dist/cli/errors.d.ts.map +1 -0
  62. package/dist/cli/examples.d.ts +23 -0
  63. package/dist/cli/examples.d.ts.map +1 -0
  64. package/dist/cli/index.d.ts +1 -1
  65. package/dist/cli/index.d.ts.map +1 -1
  66. package/dist/cli/index.js +2426 -6225
  67. package/dist/client/index.browser.d.ts +29 -0
  68. package/dist/client/index.browser.d.ts.map +1 -0
  69. package/dist/client/index.browser.js +64 -0
  70. package/dist/client/index.d.ts +6 -1
  71. package/dist/client/index.d.ts.map +1 -1
  72. package/dist/client/index.js +41 -21
  73. package/dist/client/live.d.ts +67 -0
  74. package/dist/client/live.d.ts.map +1 -0
  75. package/dist/client/reactive.d.ts +31 -0
  76. package/dist/client/reactive.d.ts.map +1 -0
  77. package/dist/client/sdk.browser.d.ts +104 -0
  78. package/dist/client/sdk.browser.d.ts.map +1 -0
  79. package/dist/client/sdk.browser.js +9 -0
  80. package/dist/client/sdk.d.ts +26 -2
  81. package/dist/client/sdk.d.ts.map +1 -1
  82. package/dist/client/sdk.js +9 -0
  83. package/dist/client/vcs-client.d.ts +129 -0
  84. package/dist/client/vcs-client.d.ts.map +1 -0
  85. package/dist/cms/index.js +171 -163
  86. package/dist/{config-8hczw0rs.js → config-PFTP67TR.js} +8 -9
  87. package/dist/core/computation/index.d.ts +5 -0
  88. package/dist/core/computation/index.d.ts.map +1 -0
  89. package/dist/core/computation/rollup.d.ts +18 -0
  90. package/dist/core/computation/rollup.d.ts.map +1 -0
  91. package/dist/core/index.d.ts +5 -0
  92. package/dist/core/index.d.ts.map +1 -1
  93. package/dist/core/index.js +171 -104
  94. package/dist/core/kernel/boot-middleware.d.ts +10 -0
  95. package/dist/core/kernel/boot-middleware.d.ts.map +1 -0
  96. package/dist/core/kernel/logic-middleware.d.ts +7 -1
  97. package/dist/core/kernel/logic-middleware.d.ts.map +1 -1
  98. package/dist/core/kernel/trellis-kernel.d.ts.map +1 -1
  99. package/dist/core/ontology/types.d.ts +5 -0
  100. package/dist/core/ontology/types.d.ts.map +1 -1
  101. package/dist/core/persist/better-sqlite-backend.d.ts +9 -2
  102. package/dist/core/persist/better-sqlite-backend.d.ts.map +1 -1
  103. package/dist/core/persist/factory.d.ts +6 -7
  104. package/dist/core/persist/factory.d.ts.map +1 -1
  105. package/dist/core/persist/factory.js +2 -3
  106. package/dist/core/persist/sqljs-backend.js +2 -3
  107. package/dist/db/index.d.ts +4 -1
  108. package/dist/db/index.d.ts.map +1 -1
  109. package/dist/db/index.js +67 -54
  110. package/dist/db/inspector.js +11 -19
  111. package/dist/db/trellis.css +1 -1
  112. package/dist/decisions/index.js +9 -10
  113. package/dist/deploy-LQ7GUGJ5.js +9 -0
  114. package/dist/deploy-YNVG5E4E.js +9 -0
  115. package/dist/deploy-cli-24BCHAXY.js +67 -0
  116. package/dist/deploy-cli-C35HTITO.js +67 -0
  117. package/dist/embeddings/auto-embed.d.ts +2 -2
  118. package/dist/embeddings/auto-embed.d.ts.map +1 -1
  119. package/dist/embeddings/index.js +20 -22
  120. package/dist/embeddings/search.d.ts +2 -1
  121. package/dist/embeddings/search.d.ts.map +1 -1
  122. package/dist/embeddings/store.d.ts +25 -4
  123. package/dist/embeddings/store.d.ts.map +1 -1
  124. package/dist/engine.d.ts +59 -19
  125. package/dist/engine.d.ts.map +1 -1
  126. package/dist/import-UZEKXU3B.js +10 -0
  127. package/dist/index.js +102 -93
  128. package/dist/launch-explorer-HZ4ZJA4X.js +95 -0
  129. package/dist/links/index.js +24 -26
  130. package/dist/mcp/server.d.ts.map +1 -1
  131. package/dist/plugins/agent-memory/index.js +316 -0
  132. package/dist/plugins/idea-garden/index.js +165 -0
  133. package/dist/plugins/plan-approval/index.js +579 -0
  134. package/dist/plugins/proactive-watcher/index.js +194 -0
  135. package/dist/{index-2r4jxwnb.js → query-XYLTJYSA.js} +14 -15
  136. package/dist/react/index.js +39 -70
  137. package/dist/react/realtime.js +11 -0
  138. package/dist/react/schema-hooks.js +87 -0
  139. package/dist/realtime/broadcast-channel-transport.d.ts +43 -0
  140. package/dist/realtime/broadcast-channel-transport.d.ts.map +1 -0
  141. package/dist/realtime/durable-object-relay-transport.d.ts +96 -0
  142. package/dist/realtime/durable-object-relay-transport.d.ts.map +1 -0
  143. package/dist/realtime/index.d.ts +44 -0
  144. package/dist/realtime/index.d.ts.map +1 -0
  145. package/dist/realtime/index.js +40 -0
  146. package/dist/realtime/memory-hub.d.ts +32 -0
  147. package/dist/realtime/memory-hub.d.ts.map +1 -0
  148. package/dist/realtime/persistent-channel.d.ts +105 -0
  149. package/dist/realtime/persistent-channel.d.ts.map +1 -0
  150. package/dist/realtime/presence.d.ts +73 -0
  151. package/dist/realtime/presence.d.ts.map +1 -0
  152. package/dist/realtime/relay-persistence.d.ts +37 -0
  153. package/dist/realtime/relay-persistence.d.ts.map +1 -0
  154. package/dist/realtime/relay-persistence.js +107 -0
  155. package/dist/realtime/relay-server.d.ts +103 -0
  156. package/dist/realtime/relay-server.d.ts.map +1 -0
  157. package/dist/realtime/room.d.ts +98 -0
  158. package/dist/realtime/room.d.ts.map +1 -0
  159. package/dist/realtime/text.d.ts +73 -0
  160. package/dist/realtime/text.d.ts.map +1 -0
  161. package/dist/realtime/types.d.ts +89 -0
  162. package/dist/realtime/types.d.ts.map +1 -0
  163. package/dist/realtime/websocket-relay-transport.d.ts +28 -0
  164. package/dist/realtime/websocket-relay-transport.d.ts.map +1 -0
  165. package/dist/realtime.bundle.js +1100 -0
  166. package/dist/{remote-manager-xvbg4230.js → remote-manager-ODE3T2KR.js} +25 -15
  167. package/dist/scaffold/seed.d.ts.map +1 -1
  168. package/dist/scaffold/write.d.ts +1 -1
  169. package/dist/scaffold/write.d.ts.map +1 -1
  170. package/dist/schema/define.d.ts +137 -0
  171. package/dist/schema/define.d.ts.map +1 -0
  172. package/dist/schema/entity-projection.d.ts +34 -0
  173. package/dist/schema/entity-projection.d.ts.map +1 -0
  174. package/dist/schema/eql.d.ts +46 -0
  175. package/dist/schema/eql.d.ts.map +1 -0
  176. package/dist/schema/index.d.ts +21 -0
  177. package/dist/schema/index.d.ts.map +1 -0
  178. package/dist/schema/index.js +46 -0
  179. package/dist/schema/kernel-resolve.d.ts +21 -0
  180. package/dist/schema/kernel-resolve.d.ts.map +1 -0
  181. package/dist/schema/mutations.d.ts +20 -0
  182. package/dist/schema/mutations.d.ts.map +1 -0
  183. package/dist/schema/resolve.d.ts +21 -0
  184. package/dist/schema/resolve.d.ts.map +1 -0
  185. package/dist/server/deploy-meta.d.ts +25 -0
  186. package/dist/server/deploy-meta.d.ts.map +1 -0
  187. package/dist/server/deploy.d.ts +7 -2
  188. package/dist/server/deploy.d.ts.map +1 -1
  189. package/dist/server/index.d.ts +7 -2
  190. package/dist/server/index.d.ts.map +1 -1
  191. package/dist/server/index.js +100 -58
  192. package/dist/server/node-adapter.js +5 -104
  193. package/dist/server/realtime.d.ts +14 -3
  194. package/dist/server/realtime.d.ts.map +1 -1
  195. package/dist/server/server.d.ts +8 -16
  196. package/dist/server/server.d.ts.map +1 -1
  197. package/dist/server/sprites.d.ts +18 -1
  198. package/dist/server/sprites.d.ts.map +1 -1
  199. package/dist/server/tenancy.d.ts +4 -0
  200. package/dist/server/tenancy.d.ts.map +1 -1
  201. package/dist/server/usage-meter.d.ts +53 -0
  202. package/dist/server/usage-meter.d.ts.map +1 -0
  203. package/dist/server-MB3OPSPI.js +18 -0
  204. package/dist/server-ZVWGLLRF.js +18 -0
  205. package/dist/sprites-KQGTGM6W.js +27 -0
  206. package/dist/{sprites-vc4qbrp1.js → sprites-RU3E4XQN.js} +6 -7
  207. package/dist/svelte/index.d.ts +17 -0
  208. package/dist/svelte/index.d.ts.map +1 -0
  209. package/dist/svelte/index.js +51 -0
  210. package/dist/svelte/schema-hooks.d.ts +45 -0
  211. package/dist/svelte/schema-hooks.d.ts.map +1 -0
  212. package/dist/svelte/schema-hooks.js +71 -0
  213. package/dist/svelte/stores.d.ts +78 -0
  214. package/dist/svelte/stores.d.ts.map +1 -0
  215. package/dist/sync/http-transport.d.ts +3 -3
  216. package/dist/sync/http-transport.d.ts.map +1 -1
  217. package/dist/sync/index.d.ts +15 -1
  218. package/dist/sync/index.d.ts.map +1 -1
  219. package/dist/sync/index.js +617 -0
  220. package/dist/sync/memory-room.d.ts +37 -0
  221. package/dist/sync/memory-room.d.ts.map +1 -0
  222. package/dist/sync/memory-transport.d.ts +3 -3
  223. package/dist/sync/memory-transport.d.ts.map +1 -1
  224. package/dist/sync/partykit-room.d.ts +40 -0
  225. package/dist/sync/partykit-room.d.ts.map +1 -0
  226. package/dist/sync/partykit-transport.d.ts +84 -0
  227. package/dist/sync/partykit-transport.d.ts.map +1 -0
  228. package/dist/sync/room-core.d.ts +53 -0
  229. package/dist/sync/room-core.d.ts.map +1 -0
  230. package/dist/sync/sync-engine.d.ts +40 -2
  231. package/dist/sync/sync-engine.d.ts.map +1 -1
  232. package/dist/sync/sync-room-server.d.ts +39 -0
  233. package/dist/sync/sync-room-server.d.ts.map +1 -0
  234. package/dist/sync/types.d.ts +70 -3
  235. package/dist/sync/types.d.ts.map +1 -1
  236. package/dist/sync/vcs-sync-peer.d.ts +63 -0
  237. package/dist/sync/vcs-sync-peer.d.ts.map +1 -0
  238. package/dist/sync/ws-transport.d.ts +2 -2
  239. package/dist/sync/ws-transport.d.ts.map +1 -1
  240. package/dist/tenancy-NBLLGCNJ.js +14 -0
  241. package/dist/tenancy-POMWQP6M.js +16 -0
  242. package/dist/ui/client.html +355 -67
  243. package/dist/ui/launch-explorer.d.ts +22 -0
  244. package/dist/ui/launch-explorer.d.ts.map +1 -0
  245. package/dist/ui/server.d.ts +1 -1
  246. package/dist/ui/server.d.ts.map +1 -1
  247. package/dist/vcs/blob-store.d.ts.map +1 -1
  248. package/dist/vcs/idb-op-log.d.ts +67 -0
  249. package/dist/vcs/idb-op-log.d.ts.map +1 -0
  250. package/dist/vcs/index.d.ts +1 -0
  251. package/dist/vcs/index.d.ts.map +1 -1
  252. package/dist/vcs/index.js +81 -72
  253. package/dist/vcs/issue.d.ts +22 -5
  254. package/dist/vcs/issue.d.ts.map +1 -1
  255. package/dist/vcs/lane-materialize.d.ts +5 -0
  256. package/dist/vcs/lane-materialize.d.ts.map +1 -1
  257. package/dist/vcs/op-log.d.ts +28 -2
  258. package/dist/vcs/op-log.d.ts.map +1 -1
  259. package/dist/vcs/ops.d.ts +10 -0
  260. package/dist/vcs/ops.d.ts.map +1 -1
  261. package/dist/vcs/types.d.ts +2 -0
  262. package/dist/vcs/types.d.ts.map +1 -1
  263. package/dist/{vm-config-6xhsj6b3.js → vm-config-JI4OXKDQ.js} +9 -10
  264. package/dist/vue/hooks.d.ts +64 -0
  265. package/dist/vue/hooks.d.ts.map +1 -0
  266. package/dist/vue/index.d.ts +19 -0
  267. package/dist/vue/index.d.ts.map +1 -0
  268. package/dist/vue/index.js +59 -0
  269. package/dist/vue/schema-hooks.d.ts +41 -0
  270. package/dist/vue/schema-hooks.d.ts.map +1 -0
  271. package/dist/vue/schema-hooks.js +64 -0
  272. package/package.json +130 -17
  273. package/dist/deploy-999q207z.js +0 -10
  274. package/dist/engine-y0724kjq.js +0 -8
  275. package/dist/import-s2b8e0ft.js +0 -11
  276. package/dist/index-a76rekgs.js +0 -67
  277. package/dist/index-c9h37r6h.js +0 -1
  278. package/dist/index-hr9qvv77.js +0 -860
  279. package/dist/index-k5b0xskw.js +0 -1
  280. package/dist/index-nzb3am4f.js +0 -80
  281. package/dist/index-wncptktd.js +0 -292
  282. package/dist/index-y6a4kj0p.js +0 -43
  283. package/dist/index-yhwjgfvj.js +0 -342
  284. package/dist/sdk-bepky0xs.js +0 -16
  285. package/dist/server-szdjx0nt.js +0 -13
  286. package/dist/sqlite-backend-0vsmc6qj.js +0 -8
  287. package/dist/tenancy-pjm32b4v.js +0 -14
@@ -1,33 +1,32 @@
1
- // @bun
2
1
  import {
3
- createVcsOp,
4
2
  criterionEntityId,
5
3
  decisionEntityId,
6
4
  dirEntityId,
7
5
  fileEntityId,
8
- init_ops,
9
6
  init_types,
10
7
  issueEntityId,
11
8
  laneEntityId
12
- } from "./index-nzb3am4f.js";
9
+ } from "./chunk-N6MYZT4O.js";
10
+ import {
11
+ createVcsOp,
12
+ init_ops
13
+ } from "./chunk-GLM4HGN4.js";
13
14
  import {
14
15
  __esm,
15
16
  __require
16
- } from "./index-a76rekgs.js";
17
+ } from "./chunk-KFQGP6VL.js";
17
18
 
18
19
  // src/vcs/decompose.ts
19
20
  import { dirname } from "path";
20
21
  function pickFacts(input) {
21
- if (!Array.isArray(input))
22
- return [];
22
+ if (!Array.isArray(input)) return [];
23
23
  return input.filter((item) => {
24
24
  const fact = item;
25
25
  return typeof fact.e === "string" && typeof fact.a === "string" && (typeof fact.v === "string" || typeof fact.v === "number" || typeof fact.v === "boolean");
26
26
  });
27
27
  }
28
28
  function pickLinks(input) {
29
- if (!Array.isArray(input))
30
- return [];
29
+ if (!Array.isArray(input)) return [];
31
30
  return input.filter((item) => {
32
31
  const link = item;
33
32
  return typeof link.e1 === "string" && typeof link.a === "string" && typeof link.e2 === "string";
@@ -41,8 +40,7 @@ function decompose(op) {
41
40
  deleteLinks: []
42
41
  };
43
42
  const vcs = op.vcs;
44
- if (!vcs)
45
- return result;
43
+ if (!vcs) return result;
46
44
  if (vcs.issueId && vcs.oldIssueStatus) {
47
45
  result.deleteFacts.push({
48
46
  e: issueEntityId(vcs.issueId),
@@ -52,29 +50,33 @@ function decompose(op) {
52
50
  }
53
51
  switch (op.kind) {
54
52
  case "vcs:fileAdd": {
55
- if (!vcs.filePath)
56
- break;
53
+ if (!vcs.filePath) break;
57
54
  const eid = fileEntityId(vcs.filePath);
58
55
  const dir = dirname(vcs.filePath);
59
56
  const did = dirEntityId(dir === "." ? "" : dir);
60
- result.addFacts.push({ e: eid, a: "type", v: "FileNode" }, { e: eid, a: "path", v: vcs.filePath });
57
+ result.addFacts.push(
58
+ { e: eid, a: "type", v: "FileNode" },
59
+ { e: eid, a: "path", v: vcs.filePath }
60
+ );
61
61
  if (vcs.contentHash) {
62
62
  result.addFacts.push({ e: eid, a: "contentHash", v: vcs.contentHash });
63
63
  }
64
- if (vcs.size !== undefined) {
64
+ if (vcs.size !== void 0) {
65
65
  result.addFacts.push({ e: eid, a: "size", v: vcs.size });
66
66
  }
67
67
  if (vcs.language) {
68
68
  result.addFacts.push({ e: eid, a: "language", v: vcs.language });
69
69
  }
70
70
  result.addFacts.push({ e: eid, a: "lastModified", v: op.timestamp });
71
- result.addFacts.push({ e: did, a: "type", v: "DirectoryNode" }, { e: did, a: "path", v: dir === "." ? "" : dir });
71
+ result.addFacts.push(
72
+ { e: did, a: "type", v: "DirectoryNode" },
73
+ { e: did, a: "path", v: dir === "." ? "" : dir }
74
+ );
72
75
  result.addLinks.push({ e1: did, a: "contains", e2: eid });
73
76
  break;
74
77
  }
75
78
  case "vcs:fileModify": {
76
- if (!vcs.filePath)
77
- break;
79
+ if (!vcs.filePath) break;
78
80
  const eid = fileEntityId(vcs.filePath);
79
81
  if (vcs.oldContentHash) {
80
82
  result.deleteFacts.push({
@@ -86,19 +88,21 @@ function decompose(op) {
86
88
  if (vcs.contentHash) {
87
89
  result.addFacts.push({ e: eid, a: "contentHash", v: vcs.contentHash });
88
90
  }
89
- if (vcs.size !== undefined) {
91
+ if (vcs.size !== void 0) {
90
92
  result.addFacts.push({ e: eid, a: "size", v: vcs.size });
91
93
  }
92
94
  result.addFacts.push({ e: eid, a: "lastModified", v: op.timestamp });
93
95
  break;
94
96
  }
95
97
  case "vcs:fileDelete": {
96
- if (!vcs.filePath)
97
- break;
98
+ if (!vcs.filePath) break;
98
99
  const eid = fileEntityId(vcs.filePath);
99
100
  const dir = dirname(vcs.filePath);
100
101
  const did = dirEntityId(dir === "." ? "" : dir);
101
- result.deleteFacts.push({ e: eid, a: "type", v: "FileNode" }, { e: eid, a: "path", v: vcs.filePath });
102
+ result.deleteFacts.push(
103
+ { e: eid, a: "type", v: "FileNode" },
104
+ { e: eid, a: "path", v: vcs.filePath }
105
+ );
102
106
  if (vcs.contentHash) {
103
107
  result.deleteFacts.push({
104
108
  e: eid,
@@ -110,8 +114,7 @@ function decompose(op) {
110
114
  break;
111
115
  }
112
116
  case "vcs:fileRename": {
113
- if (!vcs.filePath || !vcs.oldFilePath)
114
- break;
117
+ if (!vcs.filePath || !vcs.oldFilePath) break;
115
118
  const eid = fileEntityId(vcs.oldFilePath);
116
119
  const oldDir = dirname(vcs.oldFilePath);
117
120
  const newDir = dirname(vcs.filePath);
@@ -121,15 +124,22 @@ function decompose(op) {
121
124
  result.addFacts.push({ e: eid, a: "path", v: vcs.filePath });
122
125
  result.addFacts.push({ e: eid, a: "lastModified", v: op.timestamp });
123
126
  result.deleteLinks.push({ e1: oldDid, a: "contains", e2: eid });
124
- result.addFacts.push({ e: newDid, a: "type", v: "DirectoryNode" }, { e: newDid, a: "path", v: newDir === "." ? "" : newDir });
127
+ result.addFacts.push(
128
+ { e: newDid, a: "type", v: "DirectoryNode" },
129
+ { e: newDid, a: "path", v: newDir === "." ? "" : newDir }
130
+ );
125
131
  result.addLinks.push({ e1: newDid, a: "contains", e2: eid });
126
132
  break;
127
133
  }
128
134
  case "vcs:branchCreate": {
129
- if (!vcs.branchName)
130
- break;
135
+ if (!vcs.branchName) break;
131
136
  const bid = `branch:${vcs.branchName}`;
132
- result.addFacts.push({ e: bid, a: "type", v: "Branch" }, { e: bid, a: "name", v: vcs.branchName }, { e: bid, a: "createdAt", v: op.timestamp }, { e: bid, a: "createdBy", v: op.agentId });
137
+ result.addFacts.push(
138
+ { e: bid, a: "type", v: "Branch" },
139
+ { e: bid, a: "name", v: vcs.branchName },
140
+ { e: bid, a: "createdAt", v: op.timestamp },
141
+ { e: bid, a: "createdBy", v: op.agentId }
142
+ );
133
143
  if (vcs.targetOpHash) {
134
144
  result.addFacts.push({ e: bid, a: "headOpHash", v: vcs.targetOpHash });
135
145
  }
@@ -143,24 +153,28 @@ function decompose(op) {
143
153
  break;
144
154
  }
145
155
  case "vcs:branchDelete": {
146
- if (!vcs.branchName)
147
- break;
156
+ if (!vcs.branchName) break;
148
157
  const bid = `branch:${vcs.branchName}`;
149
- result.deleteFacts.push({ e: bid, a: "type", v: "Branch" }, { e: bid, a: "name", v: vcs.branchName });
158
+ result.deleteFacts.push(
159
+ { e: bid, a: "type", v: "Branch" },
160
+ { e: bid, a: "name", v: vcs.branchName }
161
+ );
150
162
  break;
151
163
  }
152
164
  case "vcs:branchAdvance": {
153
- if (!vcs.branchName || !vcs.targetOpHash)
154
- break;
165
+ if (!vcs.branchName || !vcs.targetOpHash) break;
155
166
  const bid = `branch:${vcs.branchName}`;
156
167
  result.addFacts.push({ e: bid, a: "headOpHash", v: vcs.targetOpHash });
157
168
  break;
158
169
  }
159
170
  case "vcs:milestoneCreate": {
160
- if (!vcs.milestoneId)
161
- break;
171
+ if (!vcs.milestoneId) break;
162
172
  const mid = vcs.milestoneId;
163
- result.addFacts.push({ e: mid, a: "type", v: "Milestone" }, { e: mid, a: "createdAt", v: op.timestamp }, { e: mid, a: "createdBy", v: op.agentId });
173
+ result.addFacts.push(
174
+ { e: mid, a: "type", v: "Milestone" },
175
+ { e: mid, a: "createdAt", v: op.timestamp },
176
+ { e: mid, a: "createdBy", v: op.agentId }
177
+ );
164
178
  if (vcs.message) {
165
179
  result.addFacts.push({ e: mid, a: "message", v: vcs.message });
166
180
  }
@@ -174,17 +188,26 @@ function decompose(op) {
174
188
  }
175
189
  case "vcs:checkpointCreate": {
176
190
  const cid = `checkpoint:${op.hash}`;
177
- result.addFacts.push({ e: cid, a: "type", v: "Checkpoint" }, { e: cid, a: "createdAt", v: op.timestamp }, { e: cid, a: "atOpHash", v: op.hash });
191
+ result.addFacts.push(
192
+ { e: cid, a: "type", v: "Checkpoint" },
193
+ { e: cid, a: "createdAt", v: op.timestamp },
194
+ { e: cid, a: "atOpHash", v: op.hash }
195
+ );
178
196
  if (vcs.trigger) {
179
197
  result.addFacts.push({ e: cid, a: "trigger", v: vcs.trigger });
180
198
  }
181
199
  break;
182
200
  }
201
+ // ----- Issue tracking -----
183
202
  case "vcs:issueCreate": {
184
- if (!vcs.issueId)
185
- break;
203
+ if (!vcs.issueId) break;
186
204
  const eid = issueEntityId(vcs.issueId);
187
- result.addFacts.push({ e: eid, a: "type", v: "Issue" }, { e: eid, a: "status", v: vcs.issueStatus ?? "backlog" }, { e: eid, a: "createdAt", v: op.timestamp }, { e: eid, a: "createdBy", v: op.agentId });
205
+ result.addFacts.push(
206
+ { e: eid, a: "type", v: "Issue" },
207
+ { e: eid, a: "status", v: vcs.issueStatus ?? "backlog" },
208
+ { e: eid, a: "createdAt", v: op.timestamp },
209
+ { e: eid, a: "createdBy", v: op.agentId }
210
+ );
188
211
  if (vcs.issueTitle) {
189
212
  result.addFacts.push({ e: eid, a: "title", v: vcs.issueTitle });
190
213
  }
@@ -218,8 +241,7 @@ function decompose(op) {
218
241
  break;
219
242
  }
220
243
  case "vcs:issueUpdate": {
221
- if (!vcs.issueId)
222
- break;
244
+ if (!vcs.issueId) break;
223
245
  const eid = issueEntityId(vcs.issueId);
224
246
  if (vcs.issueStatus) {
225
247
  result.addFacts.push({ e: eid, a: "status", v: vcs.issueStatus });
@@ -240,7 +262,7 @@ function decompose(op) {
240
262
  if (vcs.issueAssignee) {
241
263
  result.addFacts.push({ e: eid, a: "assignee", v: vcs.issueAssignee });
242
264
  }
243
- if (vcs.issueDescription !== undefined) {
265
+ if (vcs.issueDescription !== void 0) {
244
266
  result.addFacts.push({
245
267
  e: eid,
246
268
  a: "description",
@@ -264,10 +286,12 @@ function decompose(op) {
264
286
  break;
265
287
  }
266
288
  case "vcs:issueStart": {
267
- if (!vcs.issueId)
268
- break;
289
+ if (!vcs.issueId) break;
269
290
  const eid = issueEntityId(vcs.issueId);
270
- result.addFacts.push({ e: eid, a: "status", v: "in_progress" }, { e: eid, a: "startedAt", v: op.timestamp });
291
+ result.addFacts.push(
292
+ { e: eid, a: "status", v: "in_progress" },
293
+ { e: eid, a: "startedAt", v: op.timestamp }
294
+ );
271
295
  if (vcs.issueAssignee) {
272
296
  result.addFacts.push({ e: eid, a: "assignee", v: vcs.issueAssignee });
273
297
  }
@@ -281,41 +305,50 @@ function decompose(op) {
281
305
  break;
282
306
  }
283
307
  case "vcs:issuePause": {
284
- if (!vcs.issueId)
285
- break;
308
+ if (!vcs.issueId) break;
286
309
  const eid = issueEntityId(vcs.issueId);
287
- result.addFacts.push({ e: eid, a: "status", v: "paused" }, { e: eid, a: "pausedAt", v: op.timestamp });
310
+ result.addFacts.push(
311
+ { e: eid, a: "status", v: "paused" },
312
+ { e: eid, a: "pausedAt", v: op.timestamp }
313
+ );
288
314
  if (vcs.pauseNote) {
289
315
  result.addFacts.push({ e: eid, a: "pauseNote", v: vcs.pauseNote });
290
316
  }
291
317
  break;
292
318
  }
293
319
  case "vcs:issueResume": {
294
- if (!vcs.issueId)
295
- break;
320
+ if (!vcs.issueId) break;
296
321
  const eid = issueEntityId(vcs.issueId);
297
- result.addFacts.push({ e: eid, a: "status", v: "in_progress" }, { e: eid, a: "resumedAt", v: op.timestamp }, { e: eid, a: "pauseNote", v: "" });
322
+ result.addFacts.push(
323
+ { e: eid, a: "status", v: "in_progress" },
324
+ { e: eid, a: "resumedAt", v: op.timestamp },
325
+ { e: eid, a: "pauseNote", v: "" }
326
+ );
298
327
  break;
299
328
  }
300
329
  case "vcs:issueClose": {
301
- if (!vcs.issueId)
302
- break;
330
+ if (!vcs.issueId) break;
303
331
  const eid = issueEntityId(vcs.issueId);
304
- result.addFacts.push({ e: eid, a: "status", v: "closed" }, { e: eid, a: "closedAt", v: op.timestamp });
332
+ result.addFacts.push(
333
+ { e: eid, a: "status", v: "closed" },
334
+ { e: eid, a: "closedAt", v: op.timestamp }
335
+ );
305
336
  break;
306
337
  }
307
338
  case "vcs:issueReopen": {
308
- if (!vcs.issueId)
309
- break;
339
+ if (!vcs.issueId) break;
310
340
  const eid = issueEntityId(vcs.issueId);
311
341
  result.addFacts.push({ e: eid, a: "status", v: "queue" });
312
342
  break;
313
343
  }
314
344
  case "vcs:criterionAdd": {
315
- if (!vcs.criterionId || !vcs.issueId)
316
- break;
345
+ if (!vcs.criterionId || !vcs.issueId) break;
317
346
  const ceid = vcs.criterionId;
318
- result.addFacts.push({ e: ceid, a: "type", v: "Criterion" }, { e: ceid, a: "status", v: "pending" }, { e: ceid, a: "createdAt", v: op.timestamp });
347
+ result.addFacts.push(
348
+ { e: ceid, a: "type", v: "Criterion" },
349
+ { e: ceid, a: "status", v: "pending" },
350
+ { e: ceid, a: "createdAt", v: op.timestamp }
351
+ );
319
352
  if (vcs.criterionDescription) {
320
353
  result.addFacts.push({
321
354
  e: ceid,
@@ -338,8 +371,7 @@ function decompose(op) {
338
371
  break;
339
372
  }
340
373
  case "vcs:criterionUpdate": {
341
- if (!vcs.criterionId)
342
- break;
374
+ if (!vcs.criterionId) break;
343
375
  const ceid = vcs.criterionId;
344
376
  if (vcs.criterionStatus) {
345
377
  result.addFacts.push({ e: ceid, a: "status", v: vcs.criterionStatus });
@@ -354,27 +386,30 @@ function decompose(op) {
354
386
  result.addFacts.push({ e: ceid, a: "lastRunAt", v: op.timestamp });
355
387
  break;
356
388
  }
389
+ // ----- Issue blocking -----
357
390
  case "vcs:issueBlock": {
358
- if (!vcs.issueId || !vcs.blockedByIssueId)
359
- break;
391
+ if (!vcs.issueId || !vcs.blockedByIssueId) break;
360
392
  const eid = issueEntityId(vcs.issueId);
361
393
  const blockerEid = issueEntityId(vcs.blockedByIssueId);
362
394
  result.addLinks.push({ e1: eid, a: "blockedBy", e2: blockerEid });
363
395
  break;
364
396
  }
365
397
  case "vcs:issueUnblock": {
366
- if (!vcs.issueId || !vcs.blockedByIssueId)
367
- break;
398
+ if (!vcs.issueId || !vcs.blockedByIssueId) break;
368
399
  const eid = issueEntityId(vcs.issueId);
369
400
  const blockerEid = issueEntityId(vcs.blockedByIssueId);
370
401
  result.deleteLinks.push({ e1: eid, a: "blockedBy", e2: blockerEid });
371
402
  break;
372
403
  }
404
+ // ----- Decision traces -----
373
405
  case "vcs:decisionRecord": {
374
- if (!vcs.decisionId)
375
- break;
406
+ if (!vcs.decisionId) break;
376
407
  const did = decisionEntityId(vcs.decisionId);
377
- result.addFacts.push({ e: did, a: "type", v: "Decision" }, { e: did, a: "createdAt", v: op.timestamp }, { e: did, a: "createdBy", v: op.agentId });
408
+ result.addFacts.push(
409
+ { e: did, a: "type", v: "Decision" },
410
+ { e: did, a: "createdAt", v: op.timestamp },
411
+ { e: did, a: "createdBy", v: op.agentId }
412
+ );
378
413
  if (vcs.decisionToolName) {
379
414
  result.addFacts.push({
380
415
  e: did,
@@ -416,10 +451,14 @@ function decompose(op) {
416
451
  break;
417
452
  }
418
453
  case "vcs:laneCreate": {
419
- if (!vcs.laneId)
420
- break;
454
+ if (!vcs.laneId) break;
421
455
  const lid = laneEntityId(vcs.laneId);
422
- result.addFacts.push({ e: lid, a: "type", v: "AgentLane" }, { e: lid, a: "status", v: "active" }, { e: lid, a: "createdAt", v: op.timestamp }, { e: lid, a: "createdBy", v: op.agentId });
456
+ result.addFacts.push(
457
+ { e: lid, a: "type", v: "AgentLane" },
458
+ { e: lid, a: "status", v: "active" },
459
+ { e: lid, a: "createdAt", v: op.timestamp },
460
+ { e: lid, a: "createdBy", v: op.agentId }
461
+ );
423
462
  if (vcs.baseBranch) {
424
463
  result.addFacts.push({ e: lid, a: "baseBranch", v: vcs.baseBranch });
425
464
  }
@@ -459,8 +498,7 @@ function decompose(op) {
459
498
  break;
460
499
  }
461
500
  case "vcs:laneDrop": {
462
- if (!vcs.laneId)
463
- break;
501
+ if (!vcs.laneId) break;
464
502
  const lid = laneEntityId(vcs.laneId);
465
503
  if (vcs.laneStatus) {
466
504
  result.deleteFacts.push({ e: lid, a: "status", v: "active" });
@@ -469,16 +507,14 @@ function decompose(op) {
469
507
  break;
470
508
  }
471
509
  case "vcs:lanePromoteStart": {
472
- if (!vcs.laneId)
473
- break;
510
+ if (!vcs.laneId) break;
474
511
  const lid = laneEntityId(vcs.laneId);
475
512
  result.deleteFacts.push({ e: lid, a: "status", v: "active" });
476
513
  result.addFacts.push({ e: lid, a: "status", v: "promoting" });
477
514
  break;
478
515
  }
479
516
  case "vcs:lanePromoteComplete": {
480
- if (!vcs.laneId)
481
- break;
517
+ if (!vcs.laneId) break;
482
518
  const lid = laneEntityId(vcs.laneId);
483
519
  result.deleteFacts.push({ e: lid, a: "status", v: "promoting" });
484
520
  result.addFacts.push({ e: lid, a: "status", v: "promoted" });
@@ -488,13 +524,13 @@ function decompose(op) {
488
524
  break;
489
525
  }
490
526
  case "vcs:lanePromoteAbort": {
491
- if (!vcs.laneId)
492
- break;
527
+ if (!vcs.laneId) break;
493
528
  const lid = laneEntityId(vcs.laneId);
494
529
  result.deleteFacts.push({ e: lid, a: "status", v: "promoting" });
495
530
  result.addFacts.push({ e: lid, a: "status", v: "active" });
496
531
  break;
497
532
  }
533
+ // ----- EAV store (CMS / knowledge graph) -----
498
534
  case "vcs:storeAssert": {
499
535
  result.addFacts.push(...pickFacts(vcs.facts));
500
536
  break;
@@ -514,89 +550,120 @@ function decompose(op) {
514
550
  }
515
551
  return result;
516
552
  }
517
- var init_decompose = __esm(() => {
518
- init_types();
553
+ var init_decompose = __esm({
554
+ "src/vcs/decompose.ts"() {
555
+ "use strict";
556
+ init_types();
557
+ }
519
558
  });
520
559
 
521
560
  // src/vcs/blob-store.ts
522
561
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
523
562
  import { join } from "path";
524
-
525
- class BlobStore {
526
- blobDir;
527
- constructor(trellisDir) {
528
- this.blobDir = join(trellisDir, "blobs");
529
- if (!existsSync(this.blobDir)) {
530
- mkdirSync(this.blobDir, { recursive: true });
531
- }
532
- }
533
- async put(content) {
534
- const hash = await this.hash(content);
535
- const blobPath = join(this.blobDir, hash);
536
- if (!existsSync(blobPath)) {
537
- writeFileSync(blobPath, content);
538
- }
539
- return hash;
540
- }
541
- putSync(content) {
542
- const hash = this.hashSync(content);
543
- const blobPath = join(this.blobDir, hash);
544
- if (!existsSync(blobPath)) {
545
- writeFileSync(blobPath, content);
546
- }
547
- return hash;
548
- }
549
- get(hash) {
550
- const blobPath = join(this.blobDir, hash);
551
- if (!existsSync(blobPath)) {
552
- return null;
553
- }
554
- return readFileSync(blobPath);
555
- }
556
- has(hash) {
557
- return existsSync(join(this.blobDir, hash));
558
- }
559
- async hash(content) {
560
- const hashBuffer = await crypto.subtle.digest("SHA-256", content);
561
- return this.hexFromBuffer(hashBuffer);
562
- }
563
- hashSync(content) {
564
- if (typeof globalThis.Bun !== "undefined") {
565
- const hasher = new globalThis.Bun.CryptoHasher("sha256");
566
- hasher.update(content);
567
- return hasher.digest("hex");
568
- }
569
- const { createHash } = __require("crypto");
570
- return createHash("sha256").update(content).digest("hex");
571
- }
572
- count() {
573
- try {
574
- const { readdirSync } = __require("fs");
575
- return readdirSync(this.blobDir).length;
576
- } catch {
577
- return 0;
578
- }
579
- }
580
- totalSize() {
581
- try {
582
- const { readdirSync, statSync } = __require("fs");
583
- const files = readdirSync(this.blobDir);
584
- return files.reduce((sum, f) => {
563
+ var BlobStore;
564
+ var init_blob_store = __esm({
565
+ "src/vcs/blob-store.ts"() {
566
+ "use strict";
567
+ BlobStore = class {
568
+ blobDir;
569
+ constructor(trellisDir) {
570
+ this.blobDir = join(trellisDir, "blobs");
571
+ if (!existsSync(this.blobDir)) {
572
+ mkdirSync(this.blobDir, { recursive: true });
573
+ }
574
+ }
575
+ /**
576
+ * Store content and return its SHA-256 hash.
577
+ * Idempotent — storing the same content twice is a no-op.
578
+ */
579
+ async put(content) {
580
+ const hash = await this.hash(content);
581
+ const blobPath = join(this.blobDir, hash);
582
+ if (!existsSync(blobPath)) {
583
+ writeFileSync(blobPath, content);
584
+ }
585
+ return hash;
586
+ }
587
+ /**
588
+ * Synchronous put — uses Bun's sync crypto if available.
589
+ */
590
+ putSync(content) {
591
+ const hash = this.hashSync(content);
592
+ const blobPath = join(this.blobDir, hash);
593
+ if (!existsSync(blobPath)) {
594
+ writeFileSync(blobPath, content);
595
+ }
596
+ return hash;
597
+ }
598
+ /**
599
+ * Retrieve content by hash. Returns null if not found.
600
+ */
601
+ get(hash) {
602
+ const blobPath = join(this.blobDir, hash);
603
+ if (!existsSync(blobPath)) {
604
+ return null;
605
+ }
606
+ return readFileSync(blobPath);
607
+ }
608
+ /**
609
+ * Check if a blob exists.
610
+ */
611
+ has(hash) {
612
+ return existsSync(join(this.blobDir, hash));
613
+ }
614
+ /**
615
+ * Compute SHA-256 hash of content (async).
616
+ */
617
+ async hash(content) {
618
+ const hashBuffer = await crypto.subtle.digest(
619
+ "SHA-256",
620
+ content
621
+ );
622
+ return this.hexFromBuffer(hashBuffer);
623
+ }
624
+ /**
625
+ * Compute SHA-256 hash of content (sync).
626
+ * Uses Bun.CryptoHasher when running under Bun, else node:crypto.
627
+ */
628
+ hashSync(content) {
629
+ const { createHash } = __require("crypto");
630
+ return createHash("sha256").update(content).digest("hex");
631
+ }
632
+ /**
633
+ * Returns the number of blobs stored.
634
+ */
635
+ count() {
585
636
  try {
586
- return sum + statSync(join(this.blobDir, f)).size;
637
+ const { readdirSync: readdirSync2 } = __require("fs");
638
+ return readdirSync2(this.blobDir).length;
587
639
  } catch {
588
- return sum;
640
+ return 0;
589
641
  }
590
- }, 0);
591
- } catch {
592
- return 0;
593
- }
594
- }
595
- hexFromBuffer(buffer) {
596
- return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
642
+ }
643
+ /**
644
+ * Returns the total size of all blobs in bytes.
645
+ */
646
+ totalSize() {
647
+ try {
648
+ const { readdirSync: readdirSync2, statSync } = __require("fs");
649
+ const files = readdirSync2(this.blobDir);
650
+ return files.reduce((sum, f) => {
651
+ try {
652
+ return sum + statSync(join(this.blobDir, f)).size;
653
+ } catch {
654
+ return sum;
655
+ }
656
+ }, 0);
657
+ } catch {
658
+ return 0;
659
+ }
660
+ }
661
+ hexFromBuffer(buffer) {
662
+ return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
663
+ }
664
+ };
597
665
  }
598
- }
599
- var init_blob_store = () => {};
666
+ });
600
667
 
601
668
  // src/vcs/branch.ts
602
669
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
@@ -676,19 +743,23 @@ function loadBranchState(rootPath) {
676
743
  activeLaneId: state.activeLaneId
677
744
  };
678
745
  }
679
- } catch {}
746
+ } catch {
747
+ }
680
748
  }
681
749
  return { currentBranch: "main" };
682
750
  }
683
751
  var BRANCH_ADVANCE_SKIP_KINDS;
684
- var init_branch = __esm(() => {
685
- init_ops();
686
- BRANCH_ADVANCE_SKIP_KINDS = new Set([
687
- "vcs:branchAdvance",
688
- "vcs:branchCreate",
689
- "vcs:branchDelete",
690
- "vcs:checkpointCreate"
691
- ]);
752
+ var init_branch = __esm({
753
+ "src/vcs/branch.ts"() {
754
+ "use strict";
755
+ init_ops();
756
+ BRANCH_ADVANCE_SKIP_KINDS = /* @__PURE__ */ new Set([
757
+ "vcs:branchAdvance",
758
+ "vcs:branchCreate",
759
+ "vcs:branchDelete",
760
+ "vcs:checkpointCreate"
761
+ ]);
762
+ }
692
763
  });
693
764
 
694
765
  // src/vcs/milestone.ts
@@ -715,7 +786,9 @@ async function createMilestone(ctx, message, opts) {
715
786
  const toIdx = ops.findIndex((o) => o.hash === toOpHash);
716
787
  const rangeOps = fromIdx >= 0 && toIdx >= 0 ? ops.slice(fromIdx, toIdx + 1) : ops;
717
788
  const affectedFiles = [
718
- ...new Set(rangeOps.filter((o) => o.vcs?.filePath).map((o) => o.vcs.filePath))
789
+ ...new Set(
790
+ rangeOps.filter((o) => o.vcs?.filePath).map((o) => o.vcs.filePath)
791
+ )
719
792
  ];
720
793
  const op = await createVcsOp("vcs:milestoneCreate", {
721
794
  agentId: ctx.agentId,
@@ -750,8 +823,11 @@ function listMilestones(ctx) {
750
823
  };
751
824
  });
752
825
  }
753
- var init_milestone = __esm(() => {
754
- init_ops();
826
+ var init_milestone = __esm({
827
+ "src/vcs/milestone.ts"() {
828
+ "use strict";
829
+ init_ops();
830
+ }
755
831
  });
756
832
 
757
833
  // src/vcs/checkpoint.ts
@@ -777,16 +853,18 @@ function listCheckpoints(ctx) {
777
853
  };
778
854
  });
779
855
  }
780
- var init_checkpoint = __esm(() => {
781
- init_ops();
856
+ var init_checkpoint = __esm({
857
+ "src/vcs/checkpoint.ts"() {
858
+ "use strict";
859
+ init_ops();
860
+ }
782
861
  });
783
862
 
784
863
  // src/vcs/diff.ts
785
864
  function diffFileStates(stateA, stateB, blobStore) {
786
865
  const diffs = [];
787
866
  for (const [path, bState] of stateB) {
788
- if (bState.deleted)
789
- continue;
867
+ if (bState.deleted) continue;
790
868
  const aState = stateA.get(path);
791
869
  if (!aState || aState.deleted) {
792
870
  diffs.push({
@@ -805,15 +883,18 @@ function diffFileStates(stateA, stateB, blobStore) {
805
883
  const oldContent = blobStore.get(aState.contentHash);
806
884
  const newContent = blobStore.get(bState.contentHash);
807
885
  if (oldContent && newContent) {
808
- diff.unifiedDiff = generateUnifiedDiff(path, oldContent.toString("utf-8"), newContent.toString("utf-8"));
886
+ diff.unifiedDiff = generateUnifiedDiff(
887
+ path,
888
+ oldContent.toString("utf-8"),
889
+ newContent.toString("utf-8")
890
+ );
809
891
  }
810
892
  }
811
893
  diffs.push(diff);
812
894
  }
813
895
  }
814
896
  for (const [path, aState] of stateA) {
815
- if (aState.deleted)
816
- continue;
897
+ if (aState.deleted) continue;
817
898
  const bState = stateB.get(path);
818
899
  if (!bState || bState.deleted) {
819
900
  diffs.push({
@@ -836,7 +917,7 @@ function diffFileStates(stateA, stateB, blobStore) {
836
917
  };
837
918
  }
838
919
  function buildFileStateAtOp(ops, atOpHash) {
839
- const state = new Map;
920
+ const state = /* @__PURE__ */ new Map();
840
921
  for (const op of ops) {
841
922
  if (op.vcs?.filePath) {
842
923
  switch (op.kind) {
@@ -855,8 +936,7 @@ function buildFileStateAtOp(ops, atOpHash) {
855
936
  break;
856
937
  }
857
938
  }
858
- if (atOpHash && op.hash === atOpHash)
859
- break;
939
+ if (atOpHash && op.hash === atOpHash) break;
860
940
  }
861
941
  return state;
862
942
  }
@@ -866,17 +946,16 @@ function diffOpRange(ops, fromHash, toHash, blobStore) {
866
946
  return diffFileStates(stateA, stateB, blobStore);
867
947
  }
868
948
  function generateUnifiedDiff(filePath, oldText, newText, contextLines = 3) {
869
- const oldLines = oldText.split(`
870
- `);
871
- const newLines = newText.split(`
872
- `);
949
+ const oldLines = oldText.split("\n");
950
+ const newLines = newText.split("\n");
873
951
  const edits = myersDiff(oldLines, newLines);
874
952
  const hunks = buildHunks(edits, contextLines);
875
- if (hunks.length === 0)
876
- return "";
953
+ if (hunks.length === 0) return "";
877
954
  const lines = [`--- a/${filePath}`, `+++ b/${filePath}`];
878
955
  for (const hunk of hunks) {
879
- lines.push(`@@ -${hunk.oldStart},${hunk.oldCount} +${hunk.newStart},${hunk.newCount} @@`);
956
+ lines.push(
957
+ `@@ -${hunk.oldStart},${hunk.oldCount} +${hunk.newStart},${hunk.newCount} @@`
958
+ );
880
959
  for (const edit of hunk.edits) {
881
960
  switch (edit.kind) {
882
961
  case "equal":
@@ -891,14 +970,12 @@ function generateUnifiedDiff(filePath, oldText, newText, contextLines = 3) {
891
970
  }
892
971
  }
893
972
  }
894
- return lines.join(`
895
- `);
973
+ return lines.join("\n");
896
974
  }
897
975
  function myersDiff(oldLines, newLines) {
898
976
  const n = oldLines.length;
899
977
  const m = newLines.length;
900
- if (n === 0 && m === 0)
901
- return [];
978
+ if (n === 0 && m === 0) return [];
902
979
  if (n === 0)
903
980
  return newLines.map((line) => ({ kind: "insert", line }));
904
981
  if (m === 0)
@@ -908,30 +985,28 @@ function myersDiff(oldLines, newLines) {
908
985
  const v = new Int32Array(size);
909
986
  const trace = [];
910
987
  const off = max;
911
- outer:
912
- for (let d = 0;d <= max; d++) {
913
- trace.push(v.slice());
914
- for (let k = -d;k <= d; k += 2) {
915
- let x2;
916
- if (k === -d || k !== d && v[k - 1 + off] < v[k + 1 + off]) {
917
- x2 = v[k + 1 + off];
918
- } else {
919
- x2 = v[k - 1 + off] + 1;
920
- }
921
- let y2 = x2 - k;
922
- while (x2 < n && y2 < m && oldLines[x2] === newLines[y2]) {
923
- x2++;
924
- y2++;
925
- }
926
- v[k + off] = x2;
927
- if (x2 >= n && y2 >= m)
928
- break outer;
988
+ outer: for (let d = 0; d <= max; d++) {
989
+ trace.push(v.slice());
990
+ for (let k = -d; k <= d; k += 2) {
991
+ let x2;
992
+ if (k === -d || k !== d && v[k - 1 + off] < v[k + 1 + off]) {
993
+ x2 = v[k + 1 + off];
994
+ } else {
995
+ x2 = v[k - 1 + off] + 1;
929
996
  }
997
+ let y2 = x2 - k;
998
+ while (x2 < n && y2 < m && oldLines[x2] === newLines[y2]) {
999
+ x2++;
1000
+ y2++;
1001
+ }
1002
+ v[k + off] = x2;
1003
+ if (x2 >= n && y2 >= m) break outer;
930
1004
  }
1005
+ }
931
1006
  let x = n;
932
1007
  let y = m;
933
1008
  const edits = [];
934
- for (let d = trace.length - 1;d >= 0; d--) {
1009
+ for (let d = trace.length - 1; d >= 0; d--) {
935
1010
  const tv = trace[d];
936
1011
  const k = x - y;
937
1012
  let prevK;
@@ -967,22 +1042,23 @@ function myersDiff(oldLines, newLines) {
967
1042
  return edits;
968
1043
  }
969
1044
  function buildHunks(edits, contextLines) {
970
- if (edits.length === 0)
971
- return [];
1045
+ if (edits.length === 0) return [];
972
1046
  const changeIndices = [];
973
- for (let i = 0;i < edits.length; i++) {
1047
+ for (let i = 0; i < edits.length; i++) {
974
1048
  if (edits[i].kind !== "equal") {
975
1049
  changeIndices.push(i);
976
1050
  }
977
1051
  }
978
- if (changeIndices.length === 0)
979
- return [];
1052
+ if (changeIndices.length === 0) return [];
980
1053
  const hunks = [];
981
1054
  let hunkStart = Math.max(0, changeIndices[0] - contextLines);
982
1055
  let hunkEnd = Math.min(edits.length - 1, changeIndices[0] + contextLines);
983
- for (let i = 1;i < changeIndices.length; i++) {
1056
+ for (let i = 1; i < changeIndices.length; i++) {
984
1057
  const changeStart = changeIndices[i] - contextLines;
985
- const changeEnd = Math.min(edits.length - 1, changeIndices[i] + contextLines);
1058
+ const changeEnd = Math.min(
1059
+ edits.length - 1,
1060
+ changeIndices[i] + contextLines
1061
+ );
986
1062
  if (changeStart <= hunkEnd + 1) {
987
1063
  hunkEnd = changeEnd;
988
1064
  } else {
@@ -998,19 +1074,15 @@ function createHunk(edits, start, end) {
998
1074
  const hunkEdits = edits.slice(start, end + 1);
999
1075
  let oldLine = 1;
1000
1076
  let newLine = 1;
1001
- for (let i = 0;i < start; i++) {
1002
- if (edits[i].kind === "equal" || edits[i].kind === "delete")
1003
- oldLine++;
1004
- if (edits[i].kind === "equal" || edits[i].kind === "insert")
1005
- newLine++;
1077
+ for (let i = 0; i < start; i++) {
1078
+ if (edits[i].kind === "equal" || edits[i].kind === "delete") oldLine++;
1079
+ if (edits[i].kind === "equal" || edits[i].kind === "insert") newLine++;
1006
1080
  }
1007
1081
  let oldCount = 0;
1008
1082
  let newCount = 0;
1009
1083
  for (const edit of hunkEdits) {
1010
- if (edit.kind === "equal" || edit.kind === "delete")
1011
- oldCount++;
1012
- if (edit.kind === "equal" || edit.kind === "insert")
1013
- newCount++;
1084
+ if (edit.kind === "equal" || edit.kind === "delete") oldCount++;
1085
+ if (edit.kind === "equal" || edit.kind === "insert") newCount++;
1014
1086
  }
1015
1087
  return {
1016
1088
  oldStart: oldLine,
@@ -1020,28 +1092,22 @@ function createHunk(edits, start, end) {
1020
1092
  edits: hunkEdits
1021
1093
  };
1022
1094
  }
1023
- var init_diff = () => {};
1095
+ var init_diff = __esm({
1096
+ "src/vcs/diff.ts"() {
1097
+ "use strict";
1098
+ }
1099
+ });
1024
1100
 
1025
1101
  // src/vcs/merge.ts
1026
1102
  function threeWayMerge(base, ours, theirs, blobStore) {
1027
- const mergedFiles = new Map;
1103
+ const mergedFiles = /* @__PURE__ */ new Map();
1028
1104
  const conflicts = [];
1029
- const allPaths = new Set;
1030
- for (const [p, s] of base)
1031
- if (!s.deleted)
1032
- allPaths.add(p);
1033
- for (const [p, s] of ours)
1034
- if (!s.deleted)
1035
- allPaths.add(p);
1036
- for (const [p, s] of theirs)
1037
- if (!s.deleted)
1038
- allPaths.add(p);
1039
- for (const [p, s] of ours)
1040
- if (s.deleted)
1041
- allPaths.add(p);
1042
- for (const [p, s] of theirs)
1043
- if (s.deleted)
1044
- allPaths.add(p);
1105
+ const allPaths = /* @__PURE__ */ new Set();
1106
+ for (const [p, s] of base) if (!s.deleted) allPaths.add(p);
1107
+ for (const [p, s] of ours) if (!s.deleted) allPaths.add(p);
1108
+ for (const [p, s] of theirs) if (!s.deleted) allPaths.add(p);
1109
+ for (const [p, s] of ours) if (s.deleted) allPaths.add(p);
1110
+ for (const [p, s] of theirs) if (s.deleted) allPaths.add(p);
1045
1111
  for (const path of allPaths) {
1046
1112
  const b = base.get(path);
1047
1113
  const o = ours.get(path);
@@ -1049,9 +1115,9 @@ function threeWayMerge(base, ours, theirs, blobStore) {
1049
1115
  const baseExists = b && !b.deleted;
1050
1116
  const oursExists = o && !o.deleted;
1051
1117
  const theirsExists = t && !t.deleted;
1052
- const baseHash = baseExists ? b.contentHash : undefined;
1053
- const oursHash = oursExists ? o.contentHash : undefined;
1054
- const theirsHash = theirsExists ? t.contentHash : undefined;
1118
+ const baseHash = baseExists ? b.contentHash : void 0;
1119
+ const oursHash = oursExists ? o.contentHash : void 0;
1120
+ const theirsHash = theirsExists ? t.contentHash : void 0;
1055
1121
  if (oursHash === theirsHash) {
1056
1122
  continue;
1057
1123
  }
@@ -1076,9 +1142,9 @@ function threeWayMerge(base, ours, theirs, blobStore) {
1076
1142
  if (oursHash === theirsHash) {
1077
1143
  continue;
1078
1144
  }
1079
- const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : undefined;
1080
- const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : undefined;
1081
- if (oursContent !== undefined && theirsContent !== undefined) {
1145
+ const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : void 0;
1146
+ const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : void 0;
1147
+ if (oursContent !== void 0 && theirsContent !== void 0) {
1082
1148
  const textResult = threeWayTextMerge("", oursContent, theirsContent);
1083
1149
  if (textResult.clean) {
1084
1150
  mergedFiles.set(path, textResult.merged);
@@ -1100,7 +1166,7 @@ function threeWayMerge(base, ours, theirs, blobStore) {
1100
1166
  conflicts.push({
1101
1167
  path,
1102
1168
  kind: "modify-delete",
1103
- ours: oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : undefined
1169
+ ours: oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : void 0
1104
1170
  });
1105
1171
  continue;
1106
1172
  }
@@ -1108,15 +1174,15 @@ function threeWayMerge(base, ours, theirs, blobStore) {
1108
1174
  conflicts.push({
1109
1175
  path,
1110
1176
  kind: "modify-delete",
1111
- theirs: theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : undefined
1177
+ theirs: theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : void 0
1112
1178
  });
1113
1179
  continue;
1114
1180
  }
1115
1181
  if (oursExists && theirsExists && oursHash !== theirsHash) {
1116
- const baseContent = baseHash && blobStore ? blobStore.get(baseHash)?.toString("utf-8") : undefined;
1117
- const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : undefined;
1118
- const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : undefined;
1119
- if (baseContent !== undefined && oursContent !== undefined && theirsContent !== undefined) {
1182
+ const baseContent = baseHash && blobStore ? blobStore.get(baseHash)?.toString("utf-8") : void 0;
1183
+ const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : void 0;
1184
+ const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : void 0;
1185
+ if (baseContent !== void 0 && oursContent !== void 0 && theirsContent !== void 0) {
1120
1186
  const textResult = threeWayTextMerge(baseContent, oursContent, theirsContent);
1121
1187
  if (textResult.clean) {
1122
1188
  mergedFiles.set(path, textResult.merged);
@@ -1151,18 +1217,16 @@ function threeWayMerge(base, ours, theirs, blobStore) {
1151
1217
  stats: {
1152
1218
  added,
1153
1219
  modified: added,
1220
+ // in a merge context, additions from theirs are "modified"
1154
1221
  deleted,
1155
1222
  conflicted: conflicts.length
1156
1223
  }
1157
1224
  };
1158
1225
  }
1159
1226
  function threeWayTextMerge(baseText, oursText, theirsText) {
1160
- const baseLines = baseText.split(`
1161
- `);
1162
- const oursLines = oursText.split(`
1163
- `);
1164
- const theirsLines = theirsText.split(`
1165
- `);
1227
+ const baseLines = baseText.split("\n");
1228
+ const oursLines = oursText.split("\n");
1229
+ const theirsLines = theirsText.split("\n");
1166
1230
  const oursChanges = computeLineChanges(baseLines, oursLines);
1167
1231
  const theirsChanges = computeLineChanges(baseLines, theirsLines);
1168
1232
  const result = [];
@@ -1198,9 +1262,7 @@ function threeWayTextMerge(baseText, oursText, theirsText) {
1198
1262
  oursIdx += theirsChange.baseCount;
1199
1263
  theirsIdx += theirsChange.newCount;
1200
1264
  } else if (oursChange && theirsChange) {
1201
- if (oursChange.baseCount === theirsChange.baseCount && oursChange.newLines.join(`
1202
- `) === theirsChange.newLines.join(`
1203
- `)) {
1265
+ if (oursChange.baseCount === theirsChange.baseCount && oursChange.newLines.join("\n") === theirsChange.newLines.join("\n")) {
1204
1266
  applyChange(oursChange, result);
1205
1267
  baseIdx += oursChange.baseCount;
1206
1268
  oursIdx += oursChange.newCount;
@@ -1208,11 +1270,9 @@ function threeWayTextMerge(baseText, oursText, theirsText) {
1208
1270
  } else {
1209
1271
  clean = false;
1210
1272
  result.push("<<<<<<< ours");
1211
- for (const line of oursChange.newLines)
1212
- result.push(line);
1273
+ for (const line of oursChange.newLines) result.push(line);
1213
1274
  result.push("=======");
1214
- for (const line of theirsChange.newLines)
1215
- result.push(line);
1275
+ for (const line of theirsChange.newLines) result.push(line);
1216
1276
  result.push(">>>>>>> theirs");
1217
1277
  baseIdx += Math.max(oursChange.baseCount, theirsChange.baseCount);
1218
1278
  oursIdx += oursChange.newCount;
@@ -1220,8 +1280,7 @@ function threeWayTextMerge(baseText, oursText, theirsText) {
1220
1280
  }
1221
1281
  }
1222
1282
  }
1223
- return { clean, merged: result.join(`
1224
- `) };
1283
+ return { clean, merged: result.join("\n") };
1225
1284
  }
1226
1285
  function applyChange(change, result) {
1227
1286
  for (const line of change.newLines) {
@@ -1229,7 +1288,7 @@ function applyChange(change, result) {
1229
1288
  }
1230
1289
  }
1231
1290
  function computeLineChanges(baseLines, newLines) {
1232
- const changes = new Map;
1291
+ const changes = /* @__PURE__ */ new Map();
1233
1292
  const matches = lcsMatch(baseLines, newLines);
1234
1293
  let baseIdx = 0;
1235
1294
  let newIdx = 0;
@@ -1266,11 +1325,13 @@ function computeLineChanges(baseLines, newLines) {
1266
1325
  function lcsMatch(a, b) {
1267
1326
  const n = a.length;
1268
1327
  const m = b.length;
1269
- if (n === 0 || m === 0)
1270
- return [];
1271
- const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
1272
- for (let i2 = 1;i2 <= n; i2++) {
1273
- for (let j2 = 1;j2 <= m; j2++) {
1328
+ if (n === 0 || m === 0) return [];
1329
+ const dp = Array.from(
1330
+ { length: n + 1 },
1331
+ () => new Array(m + 1).fill(0)
1332
+ );
1333
+ for (let i2 = 1; i2 <= n; i2++) {
1334
+ for (let j2 = 1; j2 <= m; j2++) {
1274
1335
  if (a[i2 - 1] === b[j2 - 1]) {
1275
1336
  dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
1276
1337
  } else {
@@ -1294,7 +1355,11 @@ function lcsMatch(a, b) {
1294
1355
  }
1295
1356
  return matches;
1296
1357
  }
1297
- var init_merge = () => {};
1358
+ var init_merge = __esm({
1359
+ "src/vcs/merge.ts"() {
1360
+ "use strict";
1361
+ }
1362
+ });
1298
1363
 
1299
1364
  // src/vcs/issue.ts
1300
1365
  import { exec } from "child_process";
@@ -1312,13 +1377,22 @@ import { join as join3, dirname as dirname2 } from "path";
1312
1377
  function getIssueCounterPath(rootPath) {
1313
1378
  return join3(rootPath, ".trellis", "issue-counter.json");
1314
1379
  }
1315
- function nextIssueId(rootPath) {
1380
+ function getLaneIssueCounterPath(rootPath, laneId) {
1381
+ return join3(
1382
+ rootPath,
1383
+ ".trellis",
1384
+ "issue-counters",
1385
+ `${encodeURIComponent(laneId)}.json`
1386
+ );
1387
+ }
1388
+ function nextIssueId(rootPath, laneId) {
1389
+ const laneScope = laneId?.trim();
1316
1390
  const counterPath = getIssueCounterPath(rootPath);
1317
- const dir = dirname2(counterPath);
1318
- if (!existsSync3(dir))
1319
- mkdirSync2(dir, { recursive: true });
1320
- const lockPath = `${counterPath}.lock`;
1321
- const deadline = Date.now() + 5000;
1391
+ const scopedCounterPath = laneScope ? getLaneIssueCounterPath(rootPath, laneScope) : counterPath;
1392
+ const dir = dirname2(scopedCounterPath);
1393
+ if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
1394
+ const lockPath = `${scopedCounterPath}.lock`;
1395
+ const deadline = Date.now() + 5e3;
1322
1396
  let lockFd;
1323
1397
  while (Date.now() < deadline) {
1324
1398
  try {
@@ -1330,35 +1404,44 @@ function nextIssueId(rootPath) {
1330
1404
  }
1331
1405
  }
1332
1406
  }
1333
- if (lockFd === undefined) {
1334
- throw new Error(`Timed out waiting for issue counter lock: ${lockPath}. Another Trellis process may be stalled.`);
1407
+ if (lockFd === void 0) {
1408
+ throw new Error(
1409
+ `Timed out waiting for issue counter lock: ${lockPath}. Another Trellis process may be stalled.`
1410
+ );
1335
1411
  }
1336
1412
  try {
1337
1413
  let counter = 0;
1338
- if (existsSync3(counterPath)) {
1414
+ if (existsSync3(scopedCounterPath)) {
1339
1415
  try {
1340
- counter = JSON.parse(readFileSync3(counterPath, "utf-8")).counter ?? 0;
1341
- } catch {}
1416
+ counter = JSON.parse(readFileSync3(scopedCounterPath, "utf-8")).counter ?? 0;
1417
+ } catch {
1418
+ }
1342
1419
  }
1343
1420
  counter++;
1344
- writeFileSync3(counterPath, JSON.stringify({ counter }, null, 2));
1421
+ writeFileSync3(scopedCounterPath, JSON.stringify({ counter }, null, 2));
1422
+ if (laneScope) return `issue:${laneScope}:${counter}`;
1345
1423
  return `TRL-${counter}`;
1346
1424
  } finally {
1347
1425
  closeSync(lockFd);
1348
1426
  try {
1349
1427
  unlinkSync(lockPath);
1350
- } catch {}
1428
+ } catch {
1429
+ }
1351
1430
  }
1352
1431
  }
1353
1432
  function getIssueFact(ctx, entityId, attr) {
1354
1433
  const facts = ctx.store.getFactsByEntity(entityId);
1355
1434
  const matches = facts.filter((f) => f.a === attr);
1356
- return matches.length > 0 ? matches[matches.length - 1].v : undefined;
1435
+ return matches.length > 0 ? matches[matches.length - 1].v : void 0;
1357
1436
  }
1358
1437
  function getIssueLinks(ctx, entityId, attr) {
1359
1438
  const links = ctx.store.getLinksByEntity(entityId);
1360
1439
  return links.filter((l) => l.a === attr && l.e1 === entityId).map((l) => l.e2);
1361
1440
  }
1441
+ function issueInfoIdFromEntityId(entityId) {
1442
+ const bare = entityId.replace(/^issue:/, "");
1443
+ return bare.includes(":") ? entityId : bare;
1444
+ }
1362
1445
  function getCriteriaForIssue(ctx, issueId) {
1363
1446
  const eid = issueEntityId(issueId);
1364
1447
  const criterionLinks = ctx.store.getLinksByAttribute("criterionOf").filter((l) => l.e2 === eid);
@@ -1367,7 +1450,7 @@ function getCriteriaForIssue(ctx, issueId) {
1367
1450
  const facts = ctx.store.getFactsByEntity(ceid);
1368
1451
  const getLast = (a) => {
1369
1452
  const matches = facts.filter((f) => f.a === a);
1370
- return matches.length > 0 ? matches[matches.length - 1].v : undefined;
1453
+ return matches.length > 0 ? matches[matches.length - 1].v : void 0;
1371
1454
  };
1372
1455
  return {
1373
1456
  id: ceid,
@@ -1383,25 +1466,26 @@ function buildIssueInfo(ctx, entityId) {
1383
1466
  const facts = ctx.store.getFactsByEntity(entityId);
1384
1467
  const get = (a) => {
1385
1468
  const matches = facts.filter((f) => f.a === a);
1386
- return matches.length > 0 ? matches[matches.length - 1].v : undefined;
1469
+ return matches.length > 0 ? matches[matches.length - 1].v : void 0;
1387
1470
  };
1388
1471
  const labelsStr = get("labels");
1389
1472
  const labels = labelsStr ? labelsStr.split(",").filter(Boolean) : [];
1390
1473
  const trackedOnLinks = getIssueLinks(ctx, entityId, "trackedOn");
1391
- const branchName = trackedOnLinks.length > 0 ? trackedOnLinks[0].replace(/^branch:/, "") : undefined;
1474
+ const branchName = trackedOnLinks.length > 0 ? trackedOnLinks[0].replace(/^branch:/, "") : void 0;
1392
1475
  const childOfLinks = getIssueLinks(ctx, entityId, "childOf");
1393
- const parentId = childOfLinks.length > 0 ? childOfLinks[0].replace(/^issue:/, "") : undefined;
1394
- const bareId = entityId.replace(/^issue:/, "");
1476
+ const parentId = childOfLinks.length > 0 ? issueInfoIdFromEntityId(childOfLinks[0]) : void 0;
1477
+ const issueId = issueInfoIdFromEntityId(entityId);
1395
1478
  const blockedByLinks = getIssueLinks(ctx, entityId, "blockedBy");
1396
- const blockedBy = blockedByLinks.map((e) => e.replace(/^issue:/, ""));
1479
+ const blockedBy = blockedByLinks.map(issueInfoIdFromEntityId);
1397
1480
  const allBlockedByLinks = ctx.store.getLinksByAttribute("blockedBy");
1398
- const blocking = allBlockedByLinks.filter((l) => l.e2 === entityId).map((l) => l.e1.replace(/^issue:/, ""));
1481
+ const blocking = allBlockedByLinks.filter((l) => l.e2 === entityId).map((l) => issueInfoIdFromEntityId(l.e1));
1399
1482
  const isBlocked = blockedByLinks.some((blockerEid) => {
1400
1483
  const blockerStatus = getIssueFact(ctx, blockerEid, "status");
1401
1484
  return blockerStatus !== "closed";
1402
1485
  });
1403
1486
  return {
1404
- id: bareId,
1487
+ id: issueId,
1488
+ displayId: defaultDisplayId(issueId),
1405
1489
  title: get("title"),
1406
1490
  description: get("description"),
1407
1491
  status: get("status"),
@@ -1412,18 +1496,27 @@ function buildIssueInfo(ctx, entityId) {
1412
1496
  createdBy: get("createdBy"),
1413
1497
  startedAt: get("startedAt"),
1414
1498
  pausedAt: get("pausedAt"),
1415
- pauseNote: get("pauseNote") || undefined,
1499
+ pauseNote: get("pauseNote") || void 0,
1416
1500
  closedAt: get("closedAt"),
1417
1501
  parentId,
1418
1502
  branchName,
1419
1503
  blockedBy,
1420
1504
  blocking,
1421
1505
  isBlocked,
1422
- criteria: getCriteriaForIssue(ctx, bareId)
1506
+ criteria: getCriteriaForIssue(ctx, issueId)
1423
1507
  };
1424
1508
  }
1509
+ function defaultDisplayId(id) {
1510
+ return /^TRL-\d+$/.test(id) ? id : void 0;
1511
+ }
1425
1512
  async function createIssue(ctx, rootPath, title, opts) {
1426
- const id = nextIssueId(rootPath);
1513
+ if (opts?.parentId) {
1514
+ const parent = getIssue(ctx, opts.parentId);
1515
+ if (!parent) {
1516
+ throw new Error(`Parent issue ${opts.parentId} not found.`);
1517
+ }
1518
+ }
1519
+ const id = nextIssueId(rootPath, opts?.laneId);
1427
1520
  const op = await createVcsOp("vcs:issueCreate", {
1428
1521
  agentId: ctx.agentId,
1429
1522
  previousHash: ctx.getLastOp()?.hash,
@@ -1440,8 +1533,13 @@ async function createIssue(ctx, rootPath, title, opts) {
1440
1533
  });
1441
1534
  await ctx.applyOp(op);
1442
1535
  if (opts?.criteria) {
1443
- for (let i = 0;i < opts.criteria.length; i++) {
1444
- await addCriterion(ctx, id, opts.criteria[i].description, opts.criteria[i].command);
1536
+ for (let i = 0; i < opts.criteria.length; i++) {
1537
+ await addCriterion(
1538
+ ctx,
1539
+ id,
1540
+ opts.criteria[i].description,
1541
+ opts.criteria[i].command
1542
+ );
1445
1543
  }
1446
1544
  }
1447
1545
  return op;
@@ -1452,21 +1550,16 @@ async function updateIssue(ctx, id, updates) {
1452
1550
  throw new Error(`Issue ${id} not found.`);
1453
1551
  }
1454
1552
  const vcs = { issueId: id };
1455
- if (updates.title !== undefined)
1456
- vcs.issueTitle = updates.title;
1457
- if (updates.description !== undefined)
1458
- vcs.issueDescription = updates.description;
1459
- if (updates.status !== undefined) {
1553
+ if (updates.title !== void 0) vcs.issueTitle = updates.title;
1554
+ if (updates.description !== void 0) vcs.issueDescription = updates.description;
1555
+ if (updates.status !== void 0) {
1460
1556
  vcs.oldIssueStatus = getIssueFact(ctx, issueEntityId(id), "status");
1461
1557
  vcs.issueStatus = updates.status;
1462
1558
  }
1463
- if (updates.priority !== undefined)
1464
- vcs.issuePriority = updates.priority;
1465
- if (updates.labels !== undefined)
1466
- vcs.issueLabels = updates.labels;
1467
- if (updates.assignee !== undefined)
1468
- vcs.issueAssignee = updates.assignee;
1469
- if (updates.parentId !== undefined) {
1559
+ if (updates.priority !== void 0) vcs.issuePriority = updates.priority;
1560
+ if (updates.labels !== void 0) vcs.issueLabels = updates.labels;
1561
+ if (updates.assignee !== void 0) vcs.issueAssignee = updates.assignee;
1562
+ if (updates.parentId !== void 0) {
1470
1563
  const newParent = updates.parentId;
1471
1564
  if (newParent === id) {
1472
1565
  throw new Error(`Issue ${id} cannot be its own parent.`);
@@ -1479,10 +1572,8 @@ async function updateIssue(ctx, id, updates) {
1479
1572
  }
1480
1573
  const currentParent = issue.parentId;
1481
1574
  if (newParent !== currentParent) {
1482
- if (currentParent)
1483
- vcs.oldParentIssueId = currentParent;
1484
- if (newParent)
1485
- vcs.parentIssueId = newParent;
1575
+ if (currentParent) vcs.oldParentIssueId = currentParent;
1576
+ if (newParent) vcs.parentIssueId = newParent;
1486
1577
  }
1487
1578
  }
1488
1579
  const op = await createVcsOp("vcs:issueUpdate", {
@@ -1517,12 +1608,16 @@ async function startIssue(ctx, id, branchName) {
1517
1608
  }
1518
1609
  async function pauseIssue(ctx, id, note) {
1519
1610
  if (!note || !note.trim()) {
1520
- throw new Error(`A pause note is required. Explain why the issue is paused and what must happen before resuming.`);
1611
+ throw new Error(
1612
+ `A pause note is required. Explain why the issue is paused and what must happen before resuming.`
1613
+ );
1521
1614
  }
1522
1615
  const eid = issueEntityId(id);
1523
1616
  const status = getIssueFact(ctx, eid, "status");
1524
1617
  if (status !== "in_progress") {
1525
- throw new Error(`Cannot pause issue ${id} \u2014 status is '${status}', expected 'in_progress'.`);
1618
+ throw new Error(
1619
+ `Cannot pause issue ${id} \u2014 status is '${status}', expected 'in_progress'.`
1620
+ );
1526
1621
  }
1527
1622
  const op = await createVcsOp("vcs:issuePause", {
1528
1623
  agentId: ctx.agentId,
@@ -1540,7 +1635,9 @@ async function resumeIssue(ctx, id) {
1540
1635
  const eid = issueEntityId(id);
1541
1636
  const status = getIssueFact(ctx, eid, "status");
1542
1637
  if (status !== "paused") {
1543
- throw new Error(`Cannot resume issue ${id} \u2014 status is '${status}', expected 'paused'.`);
1638
+ throw new Error(
1639
+ `Cannot resume issue ${id} \u2014 status is '${status}', expected 'paused'.`
1640
+ );
1544
1641
  }
1545
1642
  const op = await createVcsOp("vcs:issueResume", {
1546
1643
  agentId: ctx.agentId,
@@ -1566,9 +1663,10 @@ async function closeIssue(ctx, id, opts) {
1566
1663
  const allPassed = results.length === 0 || results.every((r) => r.status === "passed");
1567
1664
  if (!allPassed) {
1568
1665
  const failing = results.filter((r) => r.status !== "passed");
1569
- throw new Error(`Cannot close issue ${id}: ${failing.length} criteria not passing:
1570
- ` + failing.map((f) => ` - ${f.description ?? f.id} (${f.status})`).join(`
1571
- `));
1666
+ throw new Error(
1667
+ `Cannot close issue ${id}: ${failing.length} criteria not passing:
1668
+ ` + failing.map((f) => ` - ${f.description ?? f.id} (${f.status})`).join("\n")
1669
+ );
1572
1670
  }
1573
1671
  if (!opts?.confirm) {
1574
1672
  return { criteriaResults: results };
@@ -1590,7 +1688,9 @@ async function triageIssue(ctx, id) {
1590
1688
  const eid = issueEntityId(id);
1591
1689
  const status = getIssueFact(ctx, eid, "status");
1592
1690
  if (status !== "backlog") {
1593
- throw new Error(`Cannot triage issue ${id} \u2014 status is '${status}', expected 'backlog'.`);
1691
+ throw new Error(
1692
+ `Cannot triage issue ${id} \u2014 status is '${status}', expected 'backlog'.`
1693
+ );
1594
1694
  }
1595
1695
  const op = await createVcsOp("vcs:issueUpdate", {
1596
1696
  agentId: ctx.agentId,
@@ -1608,7 +1708,9 @@ async function reopenIssue(ctx, id) {
1608
1708
  const eid = issueEntityId(id);
1609
1709
  const status = getIssueFact(ctx, eid, "status");
1610
1710
  if (status !== "closed") {
1611
- throw new Error(`Cannot reopen issue ${id} \u2014 status is '${status}', expected 'closed'.`);
1711
+ throw new Error(
1712
+ `Cannot reopen issue ${id} \u2014 status is '${status}', expected 'closed'.`
1713
+ );
1612
1714
  }
1613
1715
  const op = await createVcsOp("vcs:issueReopen", {
1614
1716
  agentId: ctx.agentId,
@@ -1670,7 +1772,9 @@ async function addCriterion(ctx, issueId, description, command) {
1670
1772
  async function setCriterionStatus(ctx, issueId, criterionIndex, status) {
1671
1773
  const criteria = getCriteriaForIssue(ctx, issueId);
1672
1774
  if (criterionIndex < 1 || criterionIndex > criteria.length) {
1673
- throw new Error(`Criterion index ${criterionIndex} out of range (1\u2013${criteria.length})`);
1775
+ throw new Error(
1776
+ `Criterion index ${criterionIndex} out of range (1\u2013${criteria.length})`
1777
+ );
1674
1778
  }
1675
1779
  const c = criteria[criterionIndex - 1];
1676
1780
  const op = await createVcsOp("vcs:criterionUpdate", {
@@ -1703,15 +1807,13 @@ async function runCriteria(ctx, issueId, rootPath) {
1703
1807
  try {
1704
1808
  const result = await execAsync(c.command, {
1705
1809
  cwd: rootPath,
1706
- timeout: 120000
1810
+ timeout: 12e4
1707
1811
  });
1708
- output = (result.stdout + `
1709
- ` + result.stderr).trim();
1812
+ output = (result.stdout + "\n" + result.stderr).trim();
1710
1813
  exitCode = 0;
1711
1814
  status = "passed";
1712
1815
  } catch (err) {
1713
- output = (err.stdout ?? "") + `
1714
- ` + (err.stderr ?? err.message ?? "");
1816
+ output = (err.stdout ?? "") + "\n" + (err.stderr ?? err.message ?? "");
1715
1817
  output = output.trim();
1716
1818
  exitCode = err.code ?? 1;
1717
1819
  status = "failed";
@@ -1752,7 +1854,7 @@ function listIssues(ctx, filters) {
1752
1854
  if (filters?.parentId) {
1753
1855
  issues = issues.filter((i) => i.parentId === filters.parentId);
1754
1856
  }
1755
- if (filters?.blocked !== undefined) {
1857
+ if (filters?.blocked !== void 0) {
1756
1858
  issues = issues.filter((i) => i.isBlocked === filters.blocked);
1757
1859
  }
1758
1860
  return issues;
@@ -1760,8 +1862,7 @@ function listIssues(ctx, filters) {
1760
1862
  function getIssue(ctx, id) {
1761
1863
  const eid = issueEntityId(id);
1762
1864
  const typeFact = ctx.store.getFactsByEntity(eid).find((f) => f.a === "type" && f.v === "Issue");
1763
- if (!typeFact)
1764
- return null;
1865
+ if (!typeFact) return null;
1765
1866
  return buildIssueInfo(ctx, eid);
1766
1867
  }
1767
1868
  function getActiveIssues(ctx) {
@@ -1779,23 +1880,31 @@ function checkCompletionReadiness(ctx) {
1779
1880
  } else {
1780
1881
  parts.push("\u2717 Not ready for completion:");
1781
1882
  if (queue.length > 0) {
1782
- parts.push(` Queue (${queue.length}): ${queue.map((i) => i.id).join(", ")}`);
1883
+ parts.push(
1884
+ ` Queue (${queue.length}): ${queue.map((i) => i.id).join(", ")}`
1885
+ );
1783
1886
  }
1784
1887
  if (inProgress.length > 0) {
1785
- parts.push(` In progress (${inProgress.length}): ${inProgress.map((i) => i.id).join(", ")}`);
1888
+ parts.push(
1889
+ ` In progress (${inProgress.length}): ${inProgress.map((i) => i.id).join(", ")}`
1890
+ );
1786
1891
  }
1787
1892
  if (paused.length > 0) {
1788
- parts.push(` Paused (${paused.length}): ${paused.map((i) => `${i.id}${i.pauseNote ? ` \u2014 ${i.pauseNote}` : ""}`).join(", ")}`);
1893
+ parts.push(
1894
+ ` Paused (${paused.length}): ${paused.map((i) => `${i.id}${i.pauseNote ? ` \u2014 ${i.pauseNote}` : ""}`).join(", ")}`
1895
+ );
1789
1896
  }
1790
1897
  }
1791
- return { ready, queue, paused, inProgress, summary: parts.join(`
1792
- `) };
1898
+ return { ready, queue, paused, inProgress, summary: parts.join("\n") };
1793
1899
  }
1794
1900
  var execAsync;
1795
- var init_issue = __esm(() => {
1796
- init_ops();
1797
- init_types();
1798
- execAsync = promisify(exec);
1901
+ var init_issue = __esm({
1902
+ "src/vcs/issue.ts"() {
1903
+ "use strict";
1904
+ init_ops();
1905
+ init_types();
1906
+ execAsync = promisify(exec);
1907
+ }
1799
1908
  });
1800
1909
 
1801
1910
  // src/vcs/op-log.ts
@@ -1813,172 +1922,179 @@ import {
1813
1922
  import { dirname as dirname3 } from "path";
1814
1923
  function lockTimeoutMs() {
1815
1924
  const raw = process.env.TRELLIS_OPLOG_LOCK_MS;
1816
- if (!raw)
1817
- return 5000;
1925
+ if (!raw) return 5e3;
1818
1926
  const parsed = Number(raw);
1819
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 5000;
1820
- }
1821
-
1822
- class JsonOpLog {
1823
- ops = [];
1824
- filePath;
1825
- lockPath;
1826
- constructor(filePath) {
1827
- this.filePath = filePath;
1828
- this.lockPath = `${filePath}.lock`;
1829
- }
1830
- get path() {
1831
- return this.filePath;
1832
- }
1833
- load() {
1834
- if (existsSync4(this.filePath)) {
1835
- const raw = readFileSync4(this.filePath, "utf-8");
1836
- try {
1837
- this.ops = JSON.parse(raw);
1838
- } catch {
1839
- const backupPath = this.filePath + ".bak";
1840
- if (existsSync4(backupPath)) {
1841
- const backupRaw = readFileSync4(backupPath, "utf-8");
1842
- this.ops = JSON.parse(backupRaw);
1843
- writeFileSync4(this.filePath, backupRaw);
1844
- } else {
1845
- throw new Error(`Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`);
1927
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 5e3;
1928
+ }
1929
+ var JsonOpLog, LaneOpLog;
1930
+ var init_op_log = __esm({
1931
+ "src/vcs/op-log.ts"() {
1932
+ "use strict";
1933
+ JsonOpLog = class {
1934
+ ops = [];
1935
+ filePath;
1936
+ lockPath;
1937
+ constructor(filePath) {
1938
+ this.filePath = filePath;
1939
+ this.lockPath = `${filePath}.lock`;
1940
+ }
1941
+ get path() {
1942
+ return this.filePath;
1943
+ }
1944
+ load() {
1945
+ if (existsSync4(this.filePath)) {
1946
+ const raw = readFileSync4(this.filePath, "utf-8");
1947
+ try {
1948
+ this.ops = JSON.parse(raw);
1949
+ } catch {
1950
+ const backupPath = this.filePath + ".bak";
1951
+ if (existsSync4(backupPath)) {
1952
+ const backupRaw = readFileSync4(backupPath, "utf-8");
1953
+ this.ops = JSON.parse(backupRaw);
1954
+ writeFileSync4(this.filePath, backupRaw);
1955
+ } else {
1956
+ throw new Error(
1957
+ `Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`
1958
+ );
1959
+ }
1960
+ }
1846
1961
  }
1847
1962
  }
1848
- }
1849
- }
1850
- append(op) {
1851
- this.withLock(() => {
1852
- const diskOps = this.readOpsFromDisk();
1853
- this.ops = diskOps;
1854
- if (this.ops.some((existing) => existing.hash === op.hash)) {
1855
- return;
1963
+ append(op) {
1964
+ this.withLock(() => {
1965
+ const diskOps = this.readOpsFromDisk();
1966
+ this.ops = diskOps;
1967
+ if (this.ops.some((existing) => existing.hash === op.hash)) {
1968
+ return;
1969
+ }
1970
+ this.ops.push(op);
1971
+ this.writeOpsToDisk();
1972
+ });
1856
1973
  }
1857
- this.ops.push(op);
1858
- this.flush();
1859
- });
1860
- }
1861
- readAll() {
1862
- return [...this.ops];
1863
- }
1864
- getLastOp() {
1865
- return this.ops.length > 0 ? this.ops[this.ops.length - 1] : undefined;
1866
- }
1867
- count() {
1868
- return this.ops.length;
1869
- }
1870
- flush() {
1871
- const dir = dirname3(this.filePath);
1872
- if (!existsSync4(dir))
1873
- mkdirSync3(dir, { recursive: true });
1874
- if (existsSync4(this.filePath)) {
1875
- const backupPath = this.filePath + ".bak";
1876
- try {
1877
- copyFileSync(this.filePath, backupPath);
1878
- } catch {}
1879
- }
1880
- const tempPath = `${this.filePath}.tmp`;
1881
- writeFileSync4(tempPath, JSON.stringify(this.ops, null, 2));
1882
- renameSync(tempPath, this.filePath);
1883
- }
1884
- readOpsFromDisk() {
1885
- if (!existsSync4(this.filePath)) {
1886
- return [];
1887
- }
1888
- const raw = readFileSync4(this.filePath, "utf-8");
1889
- try {
1890
- const parsed = JSON.parse(raw);
1891
- return Array.isArray(parsed) ? parsed : [];
1892
- } catch {
1893
- const backupPath = this.filePath + ".bak";
1894
- if (existsSync4(backupPath)) {
1895
- const backupRaw = readFileSync4(backupPath, "utf-8");
1896
- const parsedBackup = JSON.parse(backupRaw);
1897
- writeFileSync4(this.filePath, backupRaw);
1898
- return Array.isArray(parsedBackup) ? parsedBackup : [];
1899
- }
1900
- throw new Error(`Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`);
1901
- }
1902
- }
1903
- withLock(fn) {
1904
- const dir = dirname3(this.filePath);
1905
- if (!existsSync4(dir))
1906
- mkdirSync3(dir, { recursive: true });
1907
- const deadline = Date.now() + lockTimeoutMs();
1908
- let lockFd;
1909
- while (Date.now() < deadline) {
1910
- try {
1911
- lockFd = openSync2(this.lockPath, "wx");
1912
- break;
1913
- } catch (err) {
1914
- if (err?.code !== "EEXIST") {
1915
- throw err;
1974
+ readAll() {
1975
+ return [...this.ops];
1976
+ }
1977
+ getLastOp() {
1978
+ return this.ops.length > 0 ? this.ops[this.ops.length - 1] : void 0;
1979
+ }
1980
+ count() {
1981
+ return this.ops.length;
1982
+ }
1983
+ writeOpsToDisk() {
1984
+ const dir = dirname3(this.filePath);
1985
+ if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
1986
+ if (existsSync4(this.filePath)) {
1987
+ const backupPath = this.filePath + ".bak";
1988
+ try {
1989
+ copyFileSync(this.filePath, backupPath);
1990
+ } catch {
1991
+ }
1916
1992
  }
1993
+ const tempPath = `${this.filePath}.tmp`;
1994
+ writeFileSync4(tempPath, JSON.stringify(this.ops, null, 2));
1995
+ renameSync(tempPath, this.filePath);
1917
1996
  }
1918
- }
1919
- if (lockFd === undefined) {
1920
- throw new Error(`Timed out waiting for ops log lock: ${this.lockPath}. Another Trellis process may be stalled.`);
1921
- }
1922
- try {
1923
- fn();
1924
- } finally {
1925
- closeSync2(lockFd);
1926
- try {
1927
- unlinkSync2(this.lockPath);
1928
- } catch {}
1929
- }
1930
- }
1931
- static repair(filePath) {
1932
- if (!existsSync4(filePath)) {
1933
- return { recovered: 0, lost: 0 };
1934
- }
1935
- const raw = readFileSync4(filePath, "utf-8");
1936
- try {
1937
- const ops = JSON.parse(raw);
1938
- return { recovered: ops.length, lost: 0 };
1939
- } catch {}
1940
- const lastHash = raw.lastIndexOf('"hash": "trellis:op:');
1941
- if (lastHash === -1) {
1942
- const bakPath = filePath + ".bak";
1943
- if (existsSync4(bakPath)) {
1944
- const bakRaw = readFileSync4(bakPath, "utf-8");
1997
+ readOpsFromDisk() {
1998
+ if (!existsSync4(this.filePath)) {
1999
+ return [];
2000
+ }
2001
+ const raw = readFileSync4(this.filePath, "utf-8");
1945
2002
  try {
1946
- const ops = JSON.parse(bakRaw);
1947
- writeFileSync4(filePath, bakRaw);
2003
+ const parsed = JSON.parse(raw);
2004
+ return Array.isArray(parsed) ? parsed : [];
2005
+ } catch {
2006
+ const backupPath = this.filePath + ".bak";
2007
+ if (existsSync4(backupPath)) {
2008
+ const backupRaw = readFileSync4(backupPath, "utf-8");
2009
+ const parsedBackup = JSON.parse(backupRaw);
2010
+ writeFileSync4(this.filePath, backupRaw);
2011
+ return Array.isArray(parsedBackup) ? parsedBackup : [];
2012
+ }
2013
+ throw new Error(
2014
+ `Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`
2015
+ );
2016
+ }
2017
+ }
2018
+ withLock(fn) {
2019
+ const dir = dirname3(this.filePath);
2020
+ if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
2021
+ const deadline = Date.now() + lockTimeoutMs();
2022
+ let lockFd;
2023
+ while (Date.now() < deadline) {
2024
+ try {
2025
+ lockFd = openSync2(this.lockPath, "wx");
2026
+ break;
2027
+ } catch (err) {
2028
+ if (err?.code !== "EEXIST") {
2029
+ throw err;
2030
+ }
2031
+ }
2032
+ }
2033
+ if (lockFd === void 0) {
2034
+ throw new Error(
2035
+ `Timed out waiting for ops log lock: ${this.lockPath}. Another Trellis process may be stalled.`
2036
+ );
2037
+ }
2038
+ try {
2039
+ fn();
2040
+ } finally {
2041
+ closeSync2(lockFd);
2042
+ try {
2043
+ unlinkSync2(this.lockPath);
2044
+ } catch {
2045
+ }
2046
+ }
2047
+ }
2048
+ static repair(filePath) {
2049
+ if (!existsSync4(filePath)) {
2050
+ return { recovered: 0, lost: 0 };
2051
+ }
2052
+ const raw = readFileSync4(filePath, "utf-8");
2053
+ try {
2054
+ const ops = JSON.parse(raw);
2055
+ return { recovered: ops.length, lost: 0 };
2056
+ } catch {
2057
+ }
2058
+ const lastHash = raw.lastIndexOf('"hash": "trellis:op:');
2059
+ if (lastHash === -1) {
2060
+ const bakPath = filePath + ".bak";
2061
+ if (existsSync4(bakPath)) {
2062
+ const bakRaw = readFileSync4(bakPath, "utf-8");
2063
+ try {
2064
+ const ops = JSON.parse(bakRaw);
2065
+ writeFileSync4(filePath, bakRaw);
2066
+ return { recovered: ops.length, lost: 0 };
2067
+ } catch {
2068
+ }
2069
+ }
2070
+ writeFileSync4(filePath, "[]");
2071
+ return { recovered: 0, lost: -1 };
2072
+ }
2073
+ const endOfLine = raw.indexOf("\n", lastHash);
2074
+ const closingBrace = raw.indexOf(" }", endOfLine);
2075
+ if (closingBrace === -1) {
2076
+ writeFileSync4(filePath, "[]");
2077
+ return { recovered: 0, lost: -1 };
2078
+ }
2079
+ const fixed = raw.slice(0, closingBrace + 3) + "\n]";
2080
+ try {
2081
+ const ops = JSON.parse(fixed);
2082
+ writeFileSync4(filePath + ".corrupted", raw);
2083
+ writeFileSync4(filePath, fixed);
1948
2084
  return { recovered: ops.length, lost: 0 };
1949
- } catch {}
2085
+ } catch {
2086
+ writeFileSync4(filePath + ".corrupted", raw);
2087
+ writeFileSync4(filePath, "[]");
2088
+ return { recovered: 0, lost: -1 };
2089
+ }
1950
2090
  }
1951
- writeFileSync4(filePath, "[]");
1952
- return { recovered: 0, lost: -1 };
1953
- }
1954
- const endOfLine = raw.indexOf(`
1955
- `, lastHash);
1956
- const closingBrace = raw.indexOf(" }", endOfLine);
1957
- if (closingBrace === -1) {
1958
- writeFileSync4(filePath, "[]");
1959
- return { recovered: 0, lost: -1 };
1960
- }
1961
- const fixed = raw.slice(0, closingBrace + 3) + `
1962
- ]`;
1963
- try {
1964
- const ops = JSON.parse(fixed);
1965
- writeFileSync4(filePath + ".corrupted", raw);
1966
- writeFileSync4(filePath, fixed);
1967
- return { recovered: ops.length, lost: 0 };
1968
- } catch {
1969
- writeFileSync4(filePath + ".corrupted", raw);
1970
- writeFileSync4(filePath, "[]");
1971
- return { recovered: 0, lost: -1 };
1972
- }
2091
+ };
2092
+ LaneOpLog = class extends JsonOpLog {
2093
+ constructor(laneDir2) {
2094
+ super(`${laneDir2}/ops.json`);
2095
+ }
2096
+ };
1973
2097
  }
1974
- }
1975
- var LaneOpLog;
1976
- var init_op_log = __esm(() => {
1977
- LaneOpLog = class LaneOpLog extends JsonOpLog {
1978
- constructor(laneDir) {
1979
- super(`${laneDir}/ops.json`);
1980
- }
1981
- };
1982
2098
  });
1983
2099
 
1984
2100
  // src/vcs/lane.ts
@@ -1999,28 +2115,27 @@ function newLaneId() {
1999
2115
  }
2000
2116
  function loadLaneMeta(trellisDir, laneId) {
2001
2117
  const path = laneMetaPath(trellisDir, laneId);
2002
- if (!existsSync5(path))
2003
- return;
2118
+ if (!existsSync5(path)) return void 0;
2004
2119
  return JSON.parse(readFileSync5(path, "utf-8"));
2005
2120
  }
2006
2121
  function saveLaneMeta(trellisDir, meta) {
2007
2122
  const dir = laneDir(trellisDir, meta.id);
2008
- if (!existsSync5(dir))
2009
- mkdirSync4(dir, { recursive: true });
2010
- writeFileSync5(laneMetaPath(trellisDir, meta.id), JSON.stringify(meta, null, 2) + `
2011
- `);
2123
+ if (!existsSync5(dir)) mkdirSync4(dir, { recursive: true });
2124
+ writeFileSync5(
2125
+ laneMetaPath(trellisDir, meta.id),
2126
+ JSON.stringify(meta, null, 2) + "\n"
2127
+ );
2012
2128
  }
2013
2129
  function listLaneIds(trellisDir) {
2014
2130
  const root = lanesRoot(trellisDir);
2015
- if (!existsSync5(root))
2016
- return [];
2131
+ if (!existsSync5(root)) return [];
2017
2132
  return readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("lane-")).map((d) => d.name);
2018
2133
  }
2019
2134
  function resolveLaneHeadFromJournal(meta, laneOps) {
2020
2135
  return laneOps.at(-1)?.hash ?? meta.headOpHash ?? meta.baseOpHash;
2021
2136
  }
2022
2137
  function createLaneMeta(trellisDir, params) {
2023
- const now = new Date().toISOString();
2138
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2024
2139
  const meta = {
2025
2140
  id: newLaneId(),
2026
2141
  status: "active",
@@ -2045,15 +2160,81 @@ function createLaneMeta(trellisDir, params) {
2045
2160
  }
2046
2161
  function updateLaneHead(trellisDir, laneId, headOpHash) {
2047
2162
  const meta = loadLaneMeta(trellisDir, laneId);
2048
- if (!meta)
2049
- return;
2163
+ if (!meta) return;
2050
2164
  meta.headOpHash = headOpHash;
2051
- meta.updatedAt = new Date().toISOString();
2165
+ meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2052
2166
  saveLaneMeta(trellisDir, meta);
2053
2167
  }
2054
2168
  function listLaneMetas(trellisDir) {
2055
- return listLaneIds(trellisDir).map((id) => loadLaneMeta(trellisDir, id)).filter((m) => m !== undefined);
2169
+ return listLaneIds(trellisDir).map((id) => loadLaneMeta(trellisDir, id)).filter((m) => m !== void 0);
2056
2170
  }
2057
- var init_lane = () => {};
2171
+ var init_lane = __esm({
2172
+ "src/vcs/lane.ts"() {
2173
+ "use strict";
2174
+ }
2175
+ });
2058
2176
 
2059
- export { decompose, init_decompose, BlobStore, init_blob_store, shouldAdvanceBranchHead, getBranchHeadOpHash, createBranch, switchBranch, listBranches, deleteBranch, saveBranchState, loadBranchState, init_branch, createMilestone, listMilestones, init_milestone, createCheckpoint, listCheckpoints, init_checkpoint, diffFileStates, buildFileStateAtOp, diffOpRange, generateUnifiedDiff, myersDiff, init_diff, threeWayMerge, threeWayTextMerge, init_merge, createIssue, updateIssue, startIssue, pauseIssue, resumeIssue, closeIssue, triageIssue, reopenIssue, assignIssue, blockIssue, unblockIssue, addCriterion, setCriterionStatus, runCriteria, listIssues, getIssue, getActiveIssues, checkCompletionReadiness, init_issue, JsonOpLog, LaneOpLog, init_op_log, lanesRoot, laneDir, laneMetaPath, newLaneId, loadLaneMeta, saveLaneMeta, listLaneIds, resolveLaneHeadFromJournal, createLaneMeta, updateLaneHead, listLaneMetas, init_lane };
2177
+ export {
2178
+ decompose,
2179
+ init_decompose,
2180
+ BlobStore,
2181
+ init_blob_store,
2182
+ shouldAdvanceBranchHead,
2183
+ getBranchHeadOpHash,
2184
+ createBranch,
2185
+ switchBranch,
2186
+ listBranches,
2187
+ deleteBranch,
2188
+ saveBranchState,
2189
+ loadBranchState,
2190
+ init_branch,
2191
+ createMilestone,
2192
+ listMilestones,
2193
+ init_milestone,
2194
+ createCheckpoint,
2195
+ listCheckpoints,
2196
+ init_checkpoint,
2197
+ diffFileStates,
2198
+ buildFileStateAtOp,
2199
+ diffOpRange,
2200
+ generateUnifiedDiff,
2201
+ myersDiff,
2202
+ init_diff,
2203
+ threeWayMerge,
2204
+ threeWayTextMerge,
2205
+ init_merge,
2206
+ createIssue,
2207
+ updateIssue,
2208
+ startIssue,
2209
+ pauseIssue,
2210
+ resumeIssue,
2211
+ closeIssue,
2212
+ triageIssue,
2213
+ reopenIssue,
2214
+ assignIssue,
2215
+ blockIssue,
2216
+ unblockIssue,
2217
+ addCriterion,
2218
+ setCriterionStatus,
2219
+ runCriteria,
2220
+ listIssues,
2221
+ getIssue,
2222
+ getActiveIssues,
2223
+ checkCompletionReadiness,
2224
+ init_issue,
2225
+ JsonOpLog,
2226
+ LaneOpLog,
2227
+ init_op_log,
2228
+ lanesRoot,
2229
+ laneDir,
2230
+ laneMetaPath,
2231
+ newLaneId,
2232
+ loadLaneMeta,
2233
+ saveLaneMeta,
2234
+ listLaneIds,
2235
+ resolveLaneHeadFromJournal,
2236
+ createLaneMeta,
2237
+ updateLaneHead,
2238
+ listLaneMetas,
2239
+ init_lane
2240
+ };