trellis 3.2.0 → 3.2.3

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 (260) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +61 -171
  3. package/dist/browser/index.d.ts +18 -0
  4. package/dist/browser/index.d.ts.map +1 -0
  5. package/dist/browser/index.js +95 -0
  6. package/dist/{chunk-3ETIIPPB.js → chunk-2AACZRII.js} +312 -30
  7. package/dist/{chunk-3GDRZTAW.js → chunk-5KSGGKET.js} +1 -1
  8. package/dist/{chunk-MBNBTJCR.js → chunk-6GEZ6DN5.js} +2 -2
  9. package/dist/chunk-6RWGFC3N.js +403 -0
  10. package/dist/{chunk-X762XWVC.js → chunk-7DUMWO5L.js} +1 -1
  11. package/dist/chunk-CAG4FULI.js +121 -0
  12. package/dist/{chunk-GD5QJXSS.js → chunk-FWRS4CSC.js} +2 -2
  13. package/dist/{chunk-36VSSTL7.js → chunk-GU374KWZ.js} +1 -1
  14. package/dist/{chunk-BJ7EZ7FP.js → chunk-JHHEXEDM.js} +17 -0
  15. package/dist/{chunk-7WQGTFVJ.js → chunk-L5N5PR2S.js} +130 -75
  16. package/dist/{chunk-BXSTJVE3.js → chunk-N6MYZT4O.js} +2 -1
  17. package/dist/chunk-NWSW5YNS.js +225 -0
  18. package/dist/{chunk-HO4TURXW.js → chunk-S3XLFZ27.js} +28 -11
  19. package/dist/{chunk-BQBUVMRN.js → chunk-S6GBJ2ZB.js} +25 -14
  20. package/dist/{chunk-B3ZIFA2O.js → chunk-VBYUTRXX.js} +1 -1
  21. package/dist/cli/deploy-cli.d.ts +18 -0
  22. package/dist/cli/deploy-cli.d.ts.map +1 -0
  23. package/dist/cli/deploy-cli.js +67 -0
  24. package/dist/cli/index.d.ts +1 -1
  25. package/dist/cli/index.d.ts.map +1 -1
  26. package/dist/cli/index.js +153 -100
  27. package/dist/client/index.browser.d.ts +29 -0
  28. package/dist/client/index.browser.d.ts.map +1 -0
  29. package/dist/client/index.browser.js +64 -0
  30. package/dist/client/index.js +10 -10
  31. package/dist/client/sdk.browser.d.ts +131 -0
  32. package/dist/client/sdk.browser.d.ts.map +1 -0
  33. package/dist/{sdk-LZ7W3EEY.js → client/sdk.browser.js} +2 -2
  34. package/dist/client/sdk.js +1 -1
  35. package/dist/db/index.js +16 -16
  36. package/dist/db/inspector.js +6 -6
  37. package/dist/decisions/index.js +2 -2
  38. package/dist/embeddings/auto-embed.d.ts.map +1 -1
  39. package/dist/embeddings/index.js +1 -1
  40. package/dist/embeddings/store.d.ts.map +1 -1
  41. package/dist/engine.d.ts +27 -7
  42. package/dist/engine.d.ts.map +1 -1
  43. package/dist/index.js +6 -6
  44. package/dist/mcp/server.d.ts.map +1 -1
  45. package/dist/react/index.js +2 -2
  46. package/dist/react/schema-hooks.js +7 -7
  47. package/dist/{remote-manager-SG545WNY.js → remote-manager-ODE3T2KR.js} +5 -5
  48. package/dist/scaffold/seed.d.ts.map +1 -1
  49. package/dist/scaffold/write.d.ts +1 -1
  50. package/dist/scaffold/write.d.ts.map +1 -1
  51. package/dist/schema/index.js +4 -3
  52. package/dist/server/cors.d.ts +13 -0
  53. package/dist/server/cors.d.ts.map +1 -0
  54. package/dist/server/deploy-meta.d.ts +25 -0
  55. package/dist/server/deploy-meta.d.ts.map +1 -0
  56. package/dist/server/deploy.d.ts +8 -3
  57. package/dist/server/deploy.d.ts.map +1 -1
  58. package/dist/server/deploy.js +9 -0
  59. package/dist/server/index.d.ts +5 -2
  60. package/dist/server/index.d.ts.map +1 -1
  61. package/dist/server/index.js +51 -17
  62. package/dist/server/realtime.d.ts +4 -1
  63. package/dist/server/realtime.d.ts.map +1 -1
  64. package/dist/server/server.d.ts +1 -0
  65. package/dist/server/server.d.ts.map +1 -1
  66. package/dist/server/sprites.d.ts +18 -1
  67. package/dist/server/sprites.d.ts.map +1 -1
  68. package/dist/server/tenancy.d.ts +4 -0
  69. package/dist/server/tenancy.d.ts.map +1 -1
  70. package/dist/server/usage-meter.d.ts +53 -0
  71. package/dist/server/usage-meter.d.ts.map +1 -0
  72. package/dist/{server-IGBIIJSF.js → server-OGVWNDNK.js} +6 -1
  73. package/dist/sprites-KQGTGM6W.js +27 -0
  74. package/dist/{tenancy-OP34NFFS.js → tenancy-POMWQP6M.js} +5 -3
  75. package/dist/vcs/index.js +3 -3
  76. package/dist/vcs/types.d.ts +2 -0
  77. package/dist/vcs/types.d.ts.map +1 -1
  78. package/package.json +17 -6
  79. package/dist/better-sqlite-backend-PII64VE6.js +0 -159
  80. package/dist/better-sqlite-backend-VUBVQ7SN.js +0 -209
  81. package/dist/better-sqlite-backend-Y3AQN65E.js +0 -159
  82. package/dist/better-sqlite-backend-Y3M7DXOX.js +0 -159
  83. package/dist/boot-middleware-FJDGVUM4.js +0 -9
  84. package/dist/boot-middleware-MLJUTLUM.js +0 -9
  85. package/dist/boot-middleware-ZZPDZNYR.js +0 -9
  86. package/dist/chunk-276LKLZR.js +0 -359
  87. package/dist/chunk-2CX5UCRV.js +0 -111
  88. package/dist/chunk-2ESYSVXG.js +0 -48
  89. package/dist/chunk-2I5JU73Y.js +0 -340
  90. package/dist/chunk-2UNSRRNB.js +0 -171
  91. package/dist/chunk-335UEHQR.js +0 -907
  92. package/dist/chunk-4CF2L46N.js +0 -29
  93. package/dist/chunk-5CINODKT.js +0 -41
  94. package/dist/chunk-5ESGWJ5L.js +0 -45
  95. package/dist/chunk-5FGLQGMF.js +0 -1676
  96. package/dist/chunk-5IQZFITY.js +0 -357
  97. package/dist/chunk-5JWFAQDW.js +0 -150
  98. package/dist/chunk-62UHTVU3.js +0 -141
  99. package/dist/chunk-66UJQT2I.js +0 -35
  100. package/dist/chunk-6RNNVOAS.js +0 -355
  101. package/dist/chunk-6X23PZ6H.js +0 -969
  102. package/dist/chunk-7C7LL6MB.js +0 -315
  103. package/dist/chunk-7F4HM3JG.js +0 -394
  104. package/dist/chunk-7KJ7T4D3.js +0 -910
  105. package/dist/chunk-7QQQNUB5.js +0 -92
  106. package/dist/chunk-7QWJBS72.js +0 -946
  107. package/dist/chunk-7R36OZK3.js +0 -957
  108. package/dist/chunk-7UPKCOHE.js +0 -946
  109. package/dist/chunk-A3BONW34.js +0 -35
  110. package/dist/chunk-AHMDVHBL.js +0 -141
  111. package/dist/chunk-AW6A4OZY.js +0 -171
  112. package/dist/chunk-BJ5EKCJ5.js +0 -458
  113. package/dist/chunk-BRGYDO7D.js +0 -223
  114. package/dist/chunk-C5KPSEDN.js +0 -359
  115. package/dist/chunk-CCTNYTUC.js +0 -940
  116. package/dist/chunk-CYQ2OVD2.js +0 -35
  117. package/dist/chunk-DDAK7YOE.js +0 -299
  118. package/dist/chunk-DRILKBY6.js +0 -965
  119. package/dist/chunk-DXE24HNN.js +0 -45
  120. package/dist/chunk-E7ICUNW7.js +0 -945
  121. package/dist/chunk-EAL2PUOE.js +0 -10022
  122. package/dist/chunk-ELT7MLZB.js +0 -109
  123. package/dist/chunk-EWEIRF6G.js +0 -171
  124. package/dist/chunk-F5VDGQJC.js +0 -120
  125. package/dist/chunk-FCPL3IEQ.js +0 -98
  126. package/dist/chunk-FDPKYSV7.js +0 -96
  127. package/dist/chunk-FES3TC24.js +0 -171
  128. package/dist/chunk-FF36CQHZ.js +0 -61
  129. package/dist/chunk-FOWKR5TW.js +0 -129
  130. package/dist/chunk-FZVCXDYW.js +0 -150
  131. package/dist/chunk-G3XIHPSQ.js +0 -361
  132. package/dist/chunk-GKJLYLVU.js +0 -359
  133. package/dist/chunk-GNXHXNVQ.js +0 -113
  134. package/dist/chunk-GSR6ILTM.js +0 -277
  135. package/dist/chunk-GWRIMRSX.js +0 -45
  136. package/dist/chunk-H72UW2HJ.js +0 -45
  137. package/dist/chunk-HGI74PXB.js +0 -7417
  138. package/dist/chunk-HGRA37LO.js +0 -145
  139. package/dist/chunk-HXSRQO3L.js +0 -145
  140. package/dist/chunk-IG2X2BVO.js +0 -373
  141. package/dist/chunk-IIJVDD54.js +0 -373
  142. package/dist/chunk-IUWVEEOX.js +0 -145
  143. package/dist/chunk-IX4BBOIT.js +0 -394
  144. package/dist/chunk-IXU4RMQM.js +0 -349
  145. package/dist/chunk-J6OUIION.js +0 -857
  146. package/dist/chunk-K46RNFDE.js +0 -171
  147. package/dist/chunk-KAGU2XMY.js +0 -359
  148. package/dist/chunk-KCVYJNVX.js +0 -394
  149. package/dist/chunk-KKDRMIV6.js +0 -419
  150. package/dist/chunk-KYLIQ3YI.js +0 -399
  151. package/dist/chunk-KZYJJIRN.js +0 -946
  152. package/dist/chunk-LFOX744K.js +0 -96
  153. package/dist/chunk-LHOVJEWR.js +0 -7403
  154. package/dist/chunk-LOPXTPF3.js +0 -120
  155. package/dist/chunk-LZR3VIFU.js +0 -907
  156. package/dist/chunk-MCKGQKYU.js +0 -15
  157. package/dist/chunk-MU6EOS6F.js +0 -0
  158. package/dist/chunk-MWRQ2TXT.js +0 -357
  159. package/dist/chunk-NO73OK2I.js +0 -102
  160. package/dist/chunk-NPE2YJHK.js +0 -394
  161. package/dist/chunk-NSDXU6QX.js +0 -2213
  162. package/dist/chunk-NXIRDSZ6.js +0 -145
  163. package/dist/chunk-NZWFNHCS.js +0 -407
  164. package/dist/chunk-OB4CMMX6.js +0 -260
  165. package/dist/chunk-OBKU74FU.js +0 -7411
  166. package/dist/chunk-OQNDWRDE.js +0 -145
  167. package/dist/chunk-OVWAJMB6.js +0 -394
  168. package/dist/chunk-PDHLBTTD.js +0 -45
  169. package/dist/chunk-PEQNRKLG.js +0 -210
  170. package/dist/chunk-QERIS7QY.js +0 -7403
  171. package/dist/chunk-QHA2DM3C.js +0 -373
  172. package/dist/chunk-QLM4HSYC.js +0 -45
  173. package/dist/chunk-S2OT3TQJ.js +0 -283
  174. package/dist/chunk-S5PHSN5K.js +0 -907
  175. package/dist/chunk-SIAA4J6H.js +0 -21
  176. package/dist/chunk-SQBNLUIA.js +0 -171
  177. package/dist/chunk-STLN6A6B.js +0 -355
  178. package/dist/chunk-U7HV7GU2.js +0 -17
  179. package/dist/chunk-UGZHOGRA.js +0 -39
  180. package/dist/chunk-UICF66FS.js +0 -359
  181. package/dist/chunk-UK3EQREE.js +0 -1078
  182. package/dist/chunk-UPKPURVY.js +0 -394
  183. package/dist/chunk-URC74VCN.js +0 -959
  184. package/dist/chunk-V3G7Q3QQ.js +0 -102
  185. package/dist/chunk-VUJ6SA55.js +0 -303
  186. package/dist/chunk-VUJQLIML.js +0 -141
  187. package/dist/chunk-VWKLKLYB.js +0 -267
  188. package/dist/chunk-VYC3RZMK.js +0 -277
  189. package/dist/chunk-WMERMSWI.js +0 -154
  190. package/dist/chunk-WMR777PO.js +0 -2213
  191. package/dist/chunk-X46IECAC.js +0 -517
  192. package/dist/chunk-XEN3OEYY.js +0 -2234
  193. package/dist/chunk-XZQ66K7A.js +0 -124
  194. package/dist/chunk-YY3GF7DH.js +0 -7411
  195. package/dist/chunk-ZE5R3H4C.js +0 -907
  196. package/dist/chunk-ZHVI7BQN.js +0 -1077
  197. package/dist/chunk-ZMN5LUB7.js +0 -7411
  198. package/dist/chunk-ZUV4MD5U.js +0 -94
  199. package/dist/config-KMY6RRK3.js +0 -19
  200. package/dist/config-VDMK2DUJ.js +0 -19
  201. package/dist/db/trellis.css +0 -1
  202. package/dist/deploy-66EC752W.js +0 -9
  203. package/dist/deploy-SO7AFK6L.js +0 -9
  204. package/dist/engine-7GXBM4IT.js +0 -7
  205. package/dist/engine-NSR6BIF7.js +0 -7
  206. package/dist/factory-2P64OC7M.js +0 -34
  207. package/dist/factory-YP4ZZK5K.js +0 -34
  208. package/dist/import-AJLYHFIA.js +0 -10
  209. package/dist/launch-explorer-AI6L2AWJ.js +0 -91
  210. package/dist/query-GJL3CVGN.js +0 -31
  211. package/dist/query-MBJSK3EB.js +0 -31
  212. package/dist/query-TJHEVSKL.js +0 -31
  213. package/dist/query-WUIKOHPE.js +0 -524
  214. package/dist/remote-manager-BLJZ6KF6.js +0 -224
  215. package/dist/remote-manager-BPYE46SI.js +0 -223
  216. package/dist/remote-manager-FMESEAFA.js +0 -224
  217. package/dist/remote-manager-K2WZ5RHY.js +0 -223
  218. package/dist/remote-manager-SG5PQKCH.js +0 -224
  219. package/dist/remote-manager-WGP6MIQZ.js +0 -224
  220. package/dist/sdk-3KBB3E6V.js +0 -16
  221. package/dist/sdk-4ZQO6UTU.js +0 -16
  222. package/dist/sdk-6JA6GV3G.js +0 -16
  223. package/dist/sdk-6VTP5UTZ.js +0 -16
  224. package/dist/sdk-7VS6TYCD.js +0 -16
  225. package/dist/sdk-HQ3FTLRT.js +0 -16
  226. package/dist/sdk-HZ7NU3XE.js +0 -15
  227. package/dist/sdk-KBQE2OXT.js +0 -16
  228. package/dist/sdk-MSCDZ7JU.js +0 -15
  229. package/dist/sdk-WNZOGO3S.js +0 -15
  230. package/dist/sdk-YLV33ZCW.js +0 -9
  231. package/dist/sdk-ZSUD2LLJ.js +0 -16
  232. package/dist/server-AFXFFBWA.js +0 -11
  233. package/dist/server-AGHC4VUL.js +0 -11
  234. package/dist/server-BOH7M4TT.js +0 -13
  235. package/dist/server-DBUY2KY5.js +0 -11
  236. package/dist/server-GWBQJPRG.js +0 -11
  237. package/dist/server-JZZFULVU.js +0 -11
  238. package/dist/server-L5XAF4M5.js +0 -11
  239. package/dist/server-NYFUHANA.js +0 -12
  240. package/dist/server-OABUB2LO.js +0 -12
  241. package/dist/server-P2CKZWWV.js +0 -12
  242. package/dist/sprites-RU3E4XQN.js +0 -15
  243. package/dist/sprites-XVSMQLSI.js +0 -15
  244. package/dist/sql-wasm-FORCZFHZ.js +0 -2148
  245. package/dist/sql-wasm-JZH76RLO.js +0 -2148
  246. package/dist/sqljs-backend-CJQOIQYE.js +0 -266
  247. package/dist/sqljs-backend-KWXBUDUO.js +0 -266
  248. package/dist/state-demo.bundle.js +0 -1033
  249. package/dist/tenancy-CBWYEVUB.js +0 -11
  250. package/dist/tenancy-FO6WVYFN.js +0 -13
  251. package/dist/tenancy-FWDBESMX.js +0 -14
  252. package/dist/tenancy-HGPIS5QA.js +0 -13
  253. package/dist/tenancy-HXFALA37.js +0 -14
  254. package/dist/tenancy-S676GLID.js +0 -14
  255. package/dist/tenancy-V7ARWNNV.js +0 -14
  256. package/dist/tenancy-ZDN4GXK5.js +0 -13
  257. package/dist/tenancy-ZT5VMY7B.js +0 -14
  258. package/dist/vm-config-YZRJ3KUB.js +0 -21
  259. /package/dist/{chunk-2BRTCEHB.js → chunk-PZ4XYZ4J.js} +0 -0
  260. /package/dist/{chunk-EO3J7GRP.js → chunk-WXSWA3MV.js} +0 -0
@@ -1,2213 +0,0 @@
1
- import {
2
- createVcsOp,
3
- criterionEntityId,
4
- decisionEntityId,
5
- dirEntityId,
6
- fileEntityId,
7
- init_ops,
8
- init_types,
9
- issueEntityId,
10
- laneEntityId
11
- } from "./chunk-NO73OK2I.js";
12
- import {
13
- __esm,
14
- __require
15
- } from "./chunk-KFQGP6VL.js";
16
-
17
- // src/vcs/decompose.ts
18
- import { dirname } from "path";
19
- function pickFacts(input) {
20
- if (!Array.isArray(input)) return [];
21
- return input.filter((item) => {
22
- const fact = item;
23
- return typeof fact.e === "string" && typeof fact.a === "string" && (typeof fact.v === "string" || typeof fact.v === "number" || typeof fact.v === "boolean");
24
- });
25
- }
26
- function pickLinks(input) {
27
- if (!Array.isArray(input)) return [];
28
- return input.filter((item) => {
29
- const link = item;
30
- return typeof link.e1 === "string" && typeof link.a === "string" && typeof link.e2 === "string";
31
- });
32
- }
33
- function decompose(op) {
34
- const result = {
35
- addFacts: [],
36
- addLinks: [],
37
- deleteFacts: [],
38
- deleteLinks: []
39
- };
40
- const vcs = op.vcs;
41
- if (!vcs) return result;
42
- if (vcs.issueId && vcs.oldIssueStatus) {
43
- result.deleteFacts.push({
44
- e: issueEntityId(vcs.issueId),
45
- a: "status",
46
- v: vcs.oldIssueStatus
47
- });
48
- }
49
- switch (op.kind) {
50
- case "vcs:fileAdd": {
51
- if (!vcs.filePath) break;
52
- const eid = fileEntityId(vcs.filePath);
53
- const dir = dirname(vcs.filePath);
54
- const did = dirEntityId(dir === "." ? "" : dir);
55
- result.addFacts.push(
56
- { e: eid, a: "type", v: "FileNode" },
57
- { e: eid, a: "path", v: vcs.filePath }
58
- );
59
- if (vcs.contentHash) {
60
- result.addFacts.push({ e: eid, a: "contentHash", v: vcs.contentHash });
61
- }
62
- if (vcs.size !== void 0) {
63
- result.addFacts.push({ e: eid, a: "size", v: vcs.size });
64
- }
65
- if (vcs.language) {
66
- result.addFacts.push({ e: eid, a: "language", v: vcs.language });
67
- }
68
- result.addFacts.push({ e: eid, a: "lastModified", v: op.timestamp });
69
- result.addFacts.push(
70
- { e: did, a: "type", v: "DirectoryNode" },
71
- { e: did, a: "path", v: dir === "." ? "" : dir }
72
- );
73
- result.addLinks.push({ e1: did, a: "contains", e2: eid });
74
- break;
75
- }
76
- case "vcs:fileModify": {
77
- if (!vcs.filePath) break;
78
- const eid = fileEntityId(vcs.filePath);
79
- if (vcs.oldContentHash) {
80
- result.deleteFacts.push({
81
- e: eid,
82
- a: "contentHash",
83
- v: vcs.oldContentHash
84
- });
85
- }
86
- if (vcs.contentHash) {
87
- result.addFacts.push({ e: eid, a: "contentHash", v: vcs.contentHash });
88
- }
89
- if (vcs.size !== void 0) {
90
- result.addFacts.push({ e: eid, a: "size", v: vcs.size });
91
- }
92
- result.addFacts.push({ e: eid, a: "lastModified", v: op.timestamp });
93
- break;
94
- }
95
- case "vcs:fileDelete": {
96
- if (!vcs.filePath) break;
97
- const eid = fileEntityId(vcs.filePath);
98
- const dir = dirname(vcs.filePath);
99
- const did = dirEntityId(dir === "." ? "" : dir);
100
- result.deleteFacts.push(
101
- { e: eid, a: "type", v: "FileNode" },
102
- { e: eid, a: "path", v: vcs.filePath }
103
- );
104
- if (vcs.contentHash) {
105
- result.deleteFacts.push({
106
- e: eid,
107
- a: "contentHash",
108
- v: vcs.contentHash
109
- });
110
- }
111
- result.deleteLinks.push({ e1: did, a: "contains", e2: eid });
112
- break;
113
- }
114
- case "vcs:fileRename": {
115
- if (!vcs.filePath || !vcs.oldFilePath) break;
116
- const eid = fileEntityId(vcs.oldFilePath);
117
- const oldDir = dirname(vcs.oldFilePath);
118
- const newDir = dirname(vcs.filePath);
119
- const oldDid = dirEntityId(oldDir === "." ? "" : oldDir);
120
- const newDid = dirEntityId(newDir === "." ? "" : newDir);
121
- result.deleteFacts.push({ e: eid, a: "path", v: vcs.oldFilePath });
122
- result.addFacts.push({ e: eid, a: "path", v: vcs.filePath });
123
- result.addFacts.push({ e: eid, a: "lastModified", v: op.timestamp });
124
- result.deleteLinks.push({ e1: oldDid, a: "contains", e2: eid });
125
- result.addFacts.push(
126
- { e: newDid, a: "type", v: "DirectoryNode" },
127
- { e: newDid, a: "path", v: newDir === "." ? "" : newDir }
128
- );
129
- result.addLinks.push({ e1: newDid, a: "contains", e2: eid });
130
- break;
131
- }
132
- case "vcs:branchCreate": {
133
- if (!vcs.branchName) break;
134
- const bid = `branch:${vcs.branchName}`;
135
- result.addFacts.push(
136
- { e: bid, a: "type", v: "Branch" },
137
- { e: bid, a: "name", v: vcs.branchName },
138
- { e: bid, a: "createdAt", v: op.timestamp },
139
- { e: bid, a: "createdBy", v: op.agentId }
140
- );
141
- if (vcs.targetOpHash) {
142
- result.addFacts.push({ e: bid, a: "headOpHash", v: vcs.targetOpHash });
143
- }
144
- if (vcs.baseBranch) {
145
- result.addLinks.push({
146
- e1: bid,
147
- a: "forkedFrom",
148
- e2: `branch:${vcs.baseBranch}`
149
- });
150
- }
151
- break;
152
- }
153
- case "vcs:branchDelete": {
154
- if (!vcs.branchName) break;
155
- const bid = `branch:${vcs.branchName}`;
156
- result.deleteFacts.push(
157
- { e: bid, a: "type", v: "Branch" },
158
- { e: bid, a: "name", v: vcs.branchName }
159
- );
160
- break;
161
- }
162
- case "vcs:branchAdvance": {
163
- if (!vcs.branchName || !vcs.targetOpHash) break;
164
- const bid = `branch:${vcs.branchName}`;
165
- result.addFacts.push({ e: bid, a: "headOpHash", v: vcs.targetOpHash });
166
- break;
167
- }
168
- case "vcs:milestoneCreate": {
169
- if (!vcs.milestoneId) break;
170
- const mid = vcs.milestoneId;
171
- result.addFacts.push(
172
- { e: mid, a: "type", v: "Milestone" },
173
- { e: mid, a: "createdAt", v: op.timestamp },
174
- { e: mid, a: "createdBy", v: op.agentId }
175
- );
176
- if (vcs.message) {
177
- result.addFacts.push({ e: mid, a: "message", v: vcs.message });
178
- }
179
- if (vcs.fromOpHash) {
180
- result.addFacts.push({ e: mid, a: "fromOpHash", v: vcs.fromOpHash });
181
- }
182
- if (vcs.toOpHash) {
183
- result.addFacts.push({ e: mid, a: "toOpHash", v: vcs.toOpHash });
184
- }
185
- break;
186
- }
187
- case "vcs:checkpointCreate": {
188
- const cid = `checkpoint:${op.hash}`;
189
- result.addFacts.push(
190
- { e: cid, a: "type", v: "Checkpoint" },
191
- { e: cid, a: "createdAt", v: op.timestamp },
192
- { e: cid, a: "atOpHash", v: op.hash }
193
- );
194
- if (vcs.trigger) {
195
- result.addFacts.push({ e: cid, a: "trigger", v: vcs.trigger });
196
- }
197
- break;
198
- }
199
- // ----- Issue tracking -----
200
- case "vcs:issueCreate": {
201
- if (!vcs.issueId) break;
202
- const eid = issueEntityId(vcs.issueId);
203
- result.addFacts.push(
204
- { e: eid, a: "type", v: "Issue" },
205
- { e: eid, a: "status", v: vcs.issueStatus ?? "backlog" },
206
- { e: eid, a: "createdAt", v: op.timestamp },
207
- { e: eid, a: "createdBy", v: op.agentId }
208
- );
209
- if (vcs.issueTitle) {
210
- result.addFacts.push({ e: eid, a: "title", v: vcs.issueTitle });
211
- }
212
- if (vcs.issueDescription) {
213
- result.addFacts.push({
214
- e: eid,
215
- a: "description",
216
- v: vcs.issueDescription
217
- });
218
- }
219
- if (vcs.issuePriority) {
220
- result.addFacts.push({ e: eid, a: "priority", v: vcs.issuePriority });
221
- }
222
- if (vcs.issueLabels && vcs.issueLabels.length > 0) {
223
- result.addFacts.push({
224
- e: eid,
225
- a: "labels",
226
- v: vcs.issueLabels.join(",")
227
- });
228
- }
229
- if (vcs.issueAssignee) {
230
- result.addFacts.push({ e: eid, a: "assignee", v: vcs.issueAssignee });
231
- }
232
- if (vcs.parentIssueId) {
233
- result.addLinks.push({
234
- e1: eid,
235
- a: "childOf",
236
- e2: issueEntityId(vcs.parentIssueId)
237
- });
238
- }
239
- break;
240
- }
241
- case "vcs:issueUpdate": {
242
- if (!vcs.issueId) break;
243
- const eid = issueEntityId(vcs.issueId);
244
- if (vcs.issueStatus) {
245
- result.addFacts.push({ e: eid, a: "status", v: vcs.issueStatus });
246
- }
247
- if (vcs.issuePriority) {
248
- result.addFacts.push({ e: eid, a: "priority", v: vcs.issuePriority });
249
- }
250
- if (vcs.issueLabels) {
251
- result.addFacts.push({
252
- e: eid,
253
- a: "labels",
254
- v: vcs.issueLabels.join(",")
255
- });
256
- }
257
- if (vcs.issueTitle) {
258
- result.addFacts.push({ e: eid, a: "title", v: vcs.issueTitle });
259
- }
260
- if (vcs.issueAssignee) {
261
- result.addFacts.push({ e: eid, a: "assignee", v: vcs.issueAssignee });
262
- }
263
- if (vcs.issueDescription !== void 0) {
264
- result.addFacts.push({
265
- e: eid,
266
- a: "description",
267
- v: vcs.issueDescription
268
- });
269
- }
270
- if (vcs.oldParentIssueId) {
271
- result.deleteLinks.push({
272
- e1: eid,
273
- a: "childOf",
274
- e2: issueEntityId(vcs.oldParentIssueId)
275
- });
276
- }
277
- if (vcs.parentIssueId) {
278
- result.addLinks.push({
279
- e1: eid,
280
- a: "childOf",
281
- e2: issueEntityId(vcs.parentIssueId)
282
- });
283
- }
284
- break;
285
- }
286
- case "vcs:issueStart": {
287
- if (!vcs.issueId) break;
288
- const eid = issueEntityId(vcs.issueId);
289
- result.addFacts.push(
290
- { e: eid, a: "status", v: "in_progress" },
291
- { e: eid, a: "startedAt", v: op.timestamp }
292
- );
293
- if (vcs.issueAssignee) {
294
- result.addFacts.push({ e: eid, a: "assignee", v: vcs.issueAssignee });
295
- }
296
- if (vcs.branchName) {
297
- result.addLinks.push({
298
- e1: eid,
299
- a: "trackedOn",
300
- e2: `branch:${vcs.branchName}`
301
- });
302
- }
303
- break;
304
- }
305
- case "vcs:issuePause": {
306
- if (!vcs.issueId) break;
307
- const eid = issueEntityId(vcs.issueId);
308
- result.addFacts.push(
309
- { e: eid, a: "status", v: "paused" },
310
- { e: eid, a: "pausedAt", v: op.timestamp }
311
- );
312
- if (vcs.pauseNote) {
313
- result.addFacts.push({ e: eid, a: "pauseNote", v: vcs.pauseNote });
314
- }
315
- break;
316
- }
317
- case "vcs:issueResume": {
318
- if (!vcs.issueId) break;
319
- const eid = issueEntityId(vcs.issueId);
320
- result.addFacts.push(
321
- { e: eid, a: "status", v: "in_progress" },
322
- { e: eid, a: "resumedAt", v: op.timestamp },
323
- { e: eid, a: "pauseNote", v: "" }
324
- );
325
- break;
326
- }
327
- case "vcs:issueClose": {
328
- if (!vcs.issueId) break;
329
- const eid = issueEntityId(vcs.issueId);
330
- result.addFacts.push(
331
- { e: eid, a: "status", v: "closed" },
332
- { e: eid, a: "closedAt", v: op.timestamp }
333
- );
334
- break;
335
- }
336
- case "vcs:issueReopen": {
337
- if (!vcs.issueId) break;
338
- const eid = issueEntityId(vcs.issueId);
339
- result.addFacts.push({ e: eid, a: "status", v: "queue" });
340
- break;
341
- }
342
- case "vcs:criterionAdd": {
343
- if (!vcs.criterionId || !vcs.issueId) break;
344
- const ceid = vcs.criterionId;
345
- result.addFacts.push(
346
- { e: ceid, a: "type", v: "Criterion" },
347
- { e: ceid, a: "status", v: "pending" },
348
- { e: ceid, a: "createdAt", v: op.timestamp }
349
- );
350
- if (vcs.criterionDescription) {
351
- result.addFacts.push({
352
- e: ceid,
353
- a: "description",
354
- v: vcs.criterionDescription
355
- });
356
- }
357
- if (vcs.criterionCommand) {
358
- result.addFacts.push({
359
- e: ceid,
360
- a: "command",
361
- v: vcs.criterionCommand
362
- });
363
- }
364
- result.addLinks.push({
365
- e1: ceid,
366
- a: "criterionOf",
367
- e2: issueEntityId(vcs.issueId)
368
- });
369
- break;
370
- }
371
- case "vcs:criterionUpdate": {
372
- if (!vcs.criterionId) break;
373
- const ceid = vcs.criterionId;
374
- if (vcs.criterionStatus) {
375
- result.addFacts.push({ e: ceid, a: "status", v: vcs.criterionStatus });
376
- }
377
- if (vcs.criterionOutput) {
378
- result.addFacts.push({
379
- e: ceid,
380
- a: "lastOutput",
381
- v: vcs.criterionOutput
382
- });
383
- }
384
- result.addFacts.push({ e: ceid, a: "lastRunAt", v: op.timestamp });
385
- break;
386
- }
387
- // ----- Issue blocking -----
388
- case "vcs:issueBlock": {
389
- if (!vcs.issueId || !vcs.blockedByIssueId) break;
390
- const eid = issueEntityId(vcs.issueId);
391
- const blockerEid = issueEntityId(vcs.blockedByIssueId);
392
- result.addLinks.push({ e1: eid, a: "blockedBy", e2: blockerEid });
393
- break;
394
- }
395
- case "vcs:issueUnblock": {
396
- if (!vcs.issueId || !vcs.blockedByIssueId) break;
397
- const eid = issueEntityId(vcs.issueId);
398
- const blockerEid = issueEntityId(vcs.blockedByIssueId);
399
- result.deleteLinks.push({ e1: eid, a: "blockedBy", e2: blockerEid });
400
- break;
401
- }
402
- // ----- Decision traces -----
403
- case "vcs:decisionRecord": {
404
- if (!vcs.decisionId) break;
405
- const did = decisionEntityId(vcs.decisionId);
406
- result.addFacts.push(
407
- { e: did, a: "type", v: "Decision" },
408
- { e: did, a: "createdAt", v: op.timestamp },
409
- { e: did, a: "createdBy", v: op.agentId }
410
- );
411
- if (vcs.decisionToolName) {
412
- result.addFacts.push({
413
- e: did,
414
- a: "toolName",
415
- v: vcs.decisionToolName
416
- });
417
- }
418
- if (vcs.decisionToolInput) {
419
- result.addFacts.push({
420
- e: did,
421
- a: "toolInput",
422
- v: vcs.decisionToolInput
423
- });
424
- }
425
- if (vcs.decisionToolOutput) {
426
- result.addFacts.push({
427
- e: did,
428
- a: "outputSummary",
429
- v: vcs.decisionToolOutput
430
- });
431
- }
432
- if (vcs.decisionContext) {
433
- result.addFacts.push({ e: did, a: "context", v: vcs.decisionContext });
434
- }
435
- if (vcs.decisionRationale) {
436
- result.addFacts.push({
437
- e: did,
438
- a: "rationale",
439
- v: vcs.decisionRationale
440
- });
441
- }
442
- if (vcs.decisionAlternatives) {
443
- result.addFacts.push({
444
- e: did,
445
- a: "alternatives",
446
- v: vcs.decisionAlternatives
447
- });
448
- }
449
- break;
450
- }
451
- case "vcs:laneCreate": {
452
- if (!vcs.laneId) break;
453
- const lid = laneEntityId(vcs.laneId);
454
- result.addFacts.push(
455
- { e: lid, a: "type", v: "AgentLane" },
456
- { e: lid, a: "status", v: "active" },
457
- { e: lid, a: "createdAt", v: op.timestamp },
458
- { e: lid, a: "createdBy", v: op.agentId }
459
- );
460
- if (vcs.baseBranch) {
461
- result.addFacts.push({ e: lid, a: "baseBranch", v: vcs.baseBranch });
462
- }
463
- if (vcs.baseOpHash) {
464
- result.addFacts.push({ e: lid, a: "baseOpHash", v: vcs.baseOpHash });
465
- }
466
- if (vcs.targetBranch) {
467
- result.addFacts.push({ e: lid, a: "targetBranch", v: vcs.targetBranch });
468
- }
469
- if (vcs.baseOpHash) {
470
- result.addFacts.push({ e: lid, a: "headOpHash", v: vcs.baseOpHash });
471
- }
472
- if (vcs.issueId) {
473
- result.addFacts.push({ e: lid, a: "issueId", v: vcs.issueId });
474
- }
475
- if (vcs.sessionId) {
476
- result.addFacts.push({ e: lid, a: "sessionId", v: vcs.sessionId });
477
- }
478
- if (vcs.parentLaneId) {
479
- result.addFacts.push({ e: lid, a: "parentLaneId", v: vcs.parentLaneId });
480
- result.addLinks.push({
481
- e1: lid,
482
- a: "forkedFrom",
483
- e2: laneEntityId(vcs.parentLaneId)
484
- });
485
- }
486
- if (vcs.forkKind) {
487
- result.addFacts.push({ e: lid, a: "forkKind", v: vcs.forkKind });
488
- }
489
- if (vcs.virtualBaseOpHash) {
490
- result.addFacts.push({
491
- e: lid,
492
- a: "virtualBaseOpHash",
493
- v: vcs.virtualBaseOpHash
494
- });
495
- }
496
- break;
497
- }
498
- case "vcs:laneDrop": {
499
- if (!vcs.laneId) break;
500
- const lid = laneEntityId(vcs.laneId);
501
- if (vcs.laneStatus) {
502
- result.deleteFacts.push({ e: lid, a: "status", v: "active" });
503
- result.addFacts.push({ e: lid, a: "status", v: vcs.laneStatus });
504
- }
505
- break;
506
- }
507
- case "vcs:lanePromoteStart": {
508
- if (!vcs.laneId) break;
509
- const lid = laneEntityId(vcs.laneId);
510
- result.deleteFacts.push({ e: lid, a: "status", v: "active" });
511
- result.addFacts.push({ e: lid, a: "status", v: "promoting" });
512
- break;
513
- }
514
- case "vcs:lanePromoteComplete": {
515
- if (!vcs.laneId) break;
516
- const lid = laneEntityId(vcs.laneId);
517
- result.deleteFacts.push({ e: lid, a: "status", v: "promoting" });
518
- result.addFacts.push({ e: lid, a: "status", v: "promoted" });
519
- if (vcs.targetBranch) {
520
- result.addFacts.push({ e: lid, a: "promotedToBranch", v: vcs.targetBranch });
521
- }
522
- break;
523
- }
524
- case "vcs:lanePromoteAbort": {
525
- if (!vcs.laneId) break;
526
- const lid = laneEntityId(vcs.laneId);
527
- result.deleteFacts.push({ e: lid, a: "status", v: "promoting" });
528
- result.addFacts.push({ e: lid, a: "status", v: "active" });
529
- break;
530
- }
531
- // ----- EAV store (CMS / knowledge graph) -----
532
- case "vcs:storeAssert": {
533
- result.addFacts.push(...pickFacts(vcs.facts));
534
- break;
535
- }
536
- case "vcs:storeRetract": {
537
- result.deleteFacts.push(...pickFacts(vcs.facts));
538
- break;
539
- }
540
- case "vcs:storeLink": {
541
- result.addLinks.push(...pickLinks(vcs.links));
542
- break;
543
- }
544
- case "vcs:storeUnlink": {
545
- result.deleteLinks.push(...pickLinks(vcs.links));
546
- break;
547
- }
548
- }
549
- return result;
550
- }
551
- var init_decompose = __esm({
552
- "src/vcs/decompose.ts"() {
553
- "use strict";
554
- init_types();
555
- }
556
- });
557
-
558
- // src/vcs/blob-store.ts
559
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
560
- import { join } from "path";
561
- var BlobStore;
562
- var init_blob_store = __esm({
563
- "src/vcs/blob-store.ts"() {
564
- "use strict";
565
- BlobStore = class {
566
- blobDir;
567
- constructor(trellisDir) {
568
- this.blobDir = join(trellisDir, "blobs");
569
- if (!existsSync(this.blobDir)) {
570
- mkdirSync(this.blobDir, { recursive: true });
571
- }
572
- }
573
- /**
574
- * Store content and return its SHA-256 hash.
575
- * Idempotent — storing the same content twice is a no-op.
576
- */
577
- async put(content) {
578
- const hash = await this.hash(content);
579
- const blobPath = join(this.blobDir, hash);
580
- if (!existsSync(blobPath)) {
581
- writeFileSync(blobPath, content);
582
- }
583
- return hash;
584
- }
585
- /**
586
- * Synchronous put — uses Bun's sync crypto if available.
587
- */
588
- putSync(content) {
589
- const hash = this.hashSync(content);
590
- const blobPath = join(this.blobDir, hash);
591
- if (!existsSync(blobPath)) {
592
- writeFileSync(blobPath, content);
593
- }
594
- return hash;
595
- }
596
- /**
597
- * Retrieve content by hash. Returns null if not found.
598
- */
599
- get(hash) {
600
- const blobPath = join(this.blobDir, hash);
601
- if (!existsSync(blobPath)) {
602
- return null;
603
- }
604
- return readFileSync(blobPath);
605
- }
606
- /**
607
- * Check if a blob exists.
608
- */
609
- has(hash) {
610
- return existsSync(join(this.blobDir, hash));
611
- }
612
- /**
613
- * Compute SHA-256 hash of content (async).
614
- */
615
- async hash(content) {
616
- const hashBuffer = await crypto.subtle.digest(
617
- "SHA-256",
618
- content
619
- );
620
- return this.hexFromBuffer(hashBuffer);
621
- }
622
- /**
623
- * Compute SHA-256 hash of content (sync).
624
- * Uses Bun.CryptoHasher when running under Bun, else node:crypto.
625
- */
626
- hashSync(content) {
627
- const { createHash } = __require("crypto");
628
- return createHash("sha256").update(content).digest("hex");
629
- }
630
- /**
631
- * Returns the number of blobs stored.
632
- */
633
- count() {
634
- try {
635
- const { readdirSync: readdirSync2 } = __require("fs");
636
- return readdirSync2(this.blobDir).length;
637
- } catch {
638
- return 0;
639
- }
640
- }
641
- /**
642
- * Returns the total size of all blobs in bytes.
643
- */
644
- totalSize() {
645
- try {
646
- const { readdirSync: readdirSync2, statSync } = __require("fs");
647
- const files = readdirSync2(this.blobDir);
648
- return files.reduce((sum, f) => {
649
- try {
650
- return sum + statSync(join(this.blobDir, f)).size;
651
- } catch {
652
- return sum;
653
- }
654
- }, 0);
655
- } catch {
656
- return 0;
657
- }
658
- }
659
- hexFromBuffer(buffer) {
660
- return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
661
- }
662
- };
663
- }
664
- });
665
-
666
- // src/vcs/branch.ts
667
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
668
- import { join as join2 } from "path";
669
- function shouldAdvanceBranchHead(kind) {
670
- return !BRANCH_ADVANCE_SKIP_KINDS.has(kind);
671
- }
672
- function getBranchHeadOpHash(ctx, branchName) {
673
- const facts = ctx.store.getFactsByEntity(`branch:${branchName}`).filter((f) => f.a === "headOpHash");
674
- return facts[facts.length - 1]?.v;
675
- }
676
- async function createBranch(ctx, name, currentBranch) {
677
- const existing = ctx.store.getFactsByAttribute("type").filter((f) => f.v === "Branch" && f.e === `branch:${name}`);
678
- if (existing.length > 0) {
679
- throw new Error(`Branch '${name}' already exists`);
680
- }
681
- const op = await createVcsOp("vcs:branchCreate", {
682
- agentId: ctx.agentId,
683
- previousHash: ctx.getLastOp()?.hash,
684
- vcs: {
685
- branchName: name,
686
- baseBranch: currentBranch,
687
- targetOpHash: ctx.getLastOp()?.hash
688
- }
689
- });
690
- await ctx.applyOp(op);
691
- return op;
692
- }
693
- function switchBranch(ctx, name) {
694
- const branchFacts = ctx.store.getFactsByEntity(`branch:${name}`).filter((f) => f.a === "type" && f.v === "Branch");
695
- if (branchFacts.length === 0) {
696
- throw new Error(`Branch '${name}' does not exist`);
697
- }
698
- }
699
- function listBranches(ctx, currentBranch) {
700
- const branchFacts = ctx.store.getFactsByAttribute("type").filter((f) => f.v === "Branch");
701
- return branchFacts.map((f) => {
702
- const nameFact = ctx.store.getFactsByEntity(f.e).find((ef) => ef.a === "name");
703
- const createdFact = ctx.store.getFactsByEntity(f.e).find((ef) => ef.a === "createdAt");
704
- const name = nameFact?.v ?? f.e.replace("branch:", "");
705
- return {
706
- name,
707
- isCurrent: name === currentBranch,
708
- createdAt: createdFact?.v
709
- };
710
- });
711
- }
712
- async function deleteBranch(ctx, name, currentBranch) {
713
- if (name === currentBranch) {
714
- throw new Error(`Cannot delete the current branch '${name}'`);
715
- }
716
- const branchFacts = ctx.store.getFactsByEntity(`branch:${name}`).filter((f) => f.a === "type" && f.v === "Branch");
717
- if (branchFacts.length === 0) {
718
- throw new Error(`Branch '${name}' does not exist`);
719
- }
720
- const op = await createVcsOp("vcs:branchDelete", {
721
- agentId: ctx.agentId,
722
- previousHash: ctx.getLastOp()?.hash,
723
- vcs: { branchName: name }
724
- });
725
- await ctx.applyOp(op);
726
- return op;
727
- }
728
- function saveBranchState(rootPath, state) {
729
- const statePath = join2(rootPath, ".trellis", "state.json");
730
- writeFileSync2(statePath, JSON.stringify(state));
731
- }
732
- function loadBranchState(rootPath) {
733
- const statePath = join2(rootPath, ".trellis", "state.json");
734
- if (existsSync2(statePath)) {
735
- try {
736
- const raw = readFileSync2(statePath, "utf-8");
737
- const state = JSON.parse(raw);
738
- if (state.currentBranch) {
739
- return {
740
- currentBranch: state.currentBranch,
741
- activeLaneId: state.activeLaneId
742
- };
743
- }
744
- } catch {
745
- }
746
- }
747
- return { currentBranch: "main" };
748
- }
749
- var BRANCH_ADVANCE_SKIP_KINDS;
750
- var init_branch = __esm({
751
- "src/vcs/branch.ts"() {
752
- "use strict";
753
- init_ops();
754
- BRANCH_ADVANCE_SKIP_KINDS = /* @__PURE__ */ new Set([
755
- "vcs:branchAdvance",
756
- "vcs:branchCreate",
757
- "vcs:branchDelete",
758
- "vcs:checkpointCreate"
759
- ]);
760
- }
761
- });
762
-
763
- // src/vcs/milestone.ts
764
- async function createMilestone(ctx, message, opts) {
765
- const ops = ctx.readAllOps();
766
- const toOpHash = opts?.toOpHash ?? ops[ops.length - 1]?.hash;
767
- let fromOpHash = opts?.fromOpHash;
768
- if (!fromOpHash) {
769
- const milestones = ops.filter((o) => o.kind === "vcs:milestoneCreate");
770
- if (milestones.length > 0) {
771
- const lastMilestone = milestones[milestones.length - 1];
772
- fromOpHash = lastMilestone.vcs?.toOpHash ?? lastMilestone.hash;
773
- } else {
774
- fromOpHash = ops[0]?.hash;
775
- }
776
- }
777
- const idBase = `${message}:${Date.now()}`;
778
- const msgUint8 = new TextEncoder().encode(idBase);
779
- const hashBuffer = await crypto.subtle.digest("SHA-256", msgUint8);
780
- const hashArray = Array.from(new Uint8Array(hashBuffer));
781
- const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
782
- const milestoneId = `milestone:${hashHex.slice(0, 12)}`;
783
- const fromIdx = ops.findIndex((o) => o.hash === fromOpHash);
784
- const toIdx = ops.findIndex((o) => o.hash === toOpHash);
785
- const rangeOps = fromIdx >= 0 && toIdx >= 0 ? ops.slice(fromIdx, toIdx + 1) : ops;
786
- const affectedFiles = [
787
- ...new Set(
788
- rangeOps.filter((o) => o.vcs?.filePath).map((o) => o.vcs.filePath)
789
- )
790
- ];
791
- const op = await createVcsOp("vcs:milestoneCreate", {
792
- agentId: ctx.agentId,
793
- previousHash: ctx.getLastOp()?.hash,
794
- vcs: {
795
- milestoneId,
796
- message,
797
- fromOpHash,
798
- toOpHash
799
- }
800
- });
801
- await ctx.applyOp(op);
802
- for (const file of affectedFiles) {
803
- ctx.store.addFacts([{ e: milestoneId, a: "affectsFile", v: file }]);
804
- }
805
- return op;
806
- }
807
- function listMilestones(ctx) {
808
- const milestoneFacts = ctx.store.getFactsByAttribute("type").filter((f) => f.v === "Milestone");
809
- return milestoneFacts.map((f) => {
810
- const facts = ctx.store.getFactsByEntity(f.e);
811
- const get = (attr) => facts.find((ef) => ef.a === attr)?.v;
812
- const affectedFiles = facts.filter((ef) => ef.a === "affectsFile").map((ef) => ef.v);
813
- return {
814
- id: f.e,
815
- message: get("message"),
816
- createdAt: get("createdAt"),
817
- createdBy: get("createdBy"),
818
- fromOpHash: get("fromOpHash"),
819
- toOpHash: get("toOpHash"),
820
- affectedFiles
821
- };
822
- });
823
- }
824
- var init_milestone = __esm({
825
- "src/vcs/milestone.ts"() {
826
- "use strict";
827
- init_ops();
828
- }
829
- });
830
-
831
- // src/vcs/checkpoint.ts
832
- async function createCheckpoint(ctx, trigger = "manual") {
833
- const op = await createVcsOp("vcs:checkpointCreate", {
834
- agentId: ctx.agentId,
835
- previousHash: ctx.getLastOp()?.hash,
836
- vcs: { trigger }
837
- });
838
- await ctx.applyOp(op);
839
- return op;
840
- }
841
- function listCheckpoints(ctx) {
842
- const cpFacts = ctx.store.getFactsByAttribute("type").filter((f) => f.v === "Checkpoint");
843
- return cpFacts.map((f) => {
844
- const facts = ctx.store.getFactsByEntity(f.e);
845
- const get = (attr) => facts.find((ef) => ef.a === attr)?.v;
846
- return {
847
- id: f.e,
848
- createdAt: get("createdAt"),
849
- trigger: get("trigger"),
850
- atOpHash: get("atOpHash")
851
- };
852
- });
853
- }
854
- var init_checkpoint = __esm({
855
- "src/vcs/checkpoint.ts"() {
856
- "use strict";
857
- init_ops();
858
- }
859
- });
860
-
861
- // src/vcs/diff.ts
862
- function diffFileStates(stateA, stateB, blobStore) {
863
- const diffs = [];
864
- for (const [path, bState] of stateB) {
865
- if (bState.deleted) continue;
866
- const aState = stateA.get(path);
867
- if (!aState || aState.deleted) {
868
- diffs.push({
869
- kind: "fileAdded",
870
- path,
871
- newContentHash: bState.contentHash
872
- });
873
- } else if (aState.contentHash !== bState.contentHash) {
874
- const diff = {
875
- kind: "fileModified",
876
- path,
877
- oldContentHash: aState.contentHash,
878
- newContentHash: bState.contentHash
879
- };
880
- if (blobStore && aState.contentHash && bState.contentHash) {
881
- const oldContent = blobStore.get(aState.contentHash);
882
- const newContent = blobStore.get(bState.contentHash);
883
- if (oldContent && newContent) {
884
- diff.unifiedDiff = generateUnifiedDiff(
885
- path,
886
- oldContent.toString("utf-8"),
887
- newContent.toString("utf-8")
888
- );
889
- }
890
- }
891
- diffs.push(diff);
892
- }
893
- }
894
- for (const [path, aState] of stateA) {
895
- if (aState.deleted) continue;
896
- const bState = stateB.get(path);
897
- if (!bState || bState.deleted) {
898
- diffs.push({
899
- kind: "fileDeleted",
900
- path,
901
- oldContentHash: aState.contentHash
902
- });
903
- }
904
- }
905
- const stats = {
906
- added: diffs.filter((d) => d.kind === "fileAdded").length,
907
- modified: diffs.filter((d) => d.kind === "fileModified").length,
908
- removed: diffs.filter((d) => d.kind === "fileDeleted").length,
909
- renamed: diffs.filter((d) => d.kind === "fileRenamed").length
910
- };
911
- return {
912
- diffs,
913
- filesChanged: diffs.map((d) => d.path),
914
- stats
915
- };
916
- }
917
- function buildFileStateAtOp(ops, atOpHash) {
918
- const state = /* @__PURE__ */ new Map();
919
- for (const op of ops) {
920
- if (op.vcs?.filePath) {
921
- switch (op.kind) {
922
- case "vcs:fileAdd":
923
- case "vcs:fileModify":
924
- state.set(op.vcs.filePath, { contentHash: op.vcs.contentHash });
925
- break;
926
- case "vcs:fileDelete":
927
- state.set(op.vcs.filePath, { deleted: true });
928
- break;
929
- case "vcs:fileRename":
930
- if (op.vcs.oldFilePath) {
931
- state.set(op.vcs.oldFilePath, { deleted: true });
932
- }
933
- state.set(op.vcs.filePath, { contentHash: op.vcs.contentHash });
934
- break;
935
- }
936
- }
937
- if (atOpHash && op.hash === atOpHash) break;
938
- }
939
- return state;
940
- }
941
- function diffOpRange(ops, fromHash, toHash, blobStore) {
942
- const stateA = buildFileStateAtOp(ops, fromHash);
943
- const stateB = buildFileStateAtOp(ops, toHash);
944
- return diffFileStates(stateA, stateB, blobStore);
945
- }
946
- function generateUnifiedDiff(filePath, oldText, newText, contextLines = 3) {
947
- const oldLines = oldText.split("\n");
948
- const newLines = newText.split("\n");
949
- const edits = myersDiff(oldLines, newLines);
950
- const hunks = buildHunks(edits, contextLines);
951
- if (hunks.length === 0) return "";
952
- const lines = [`--- a/${filePath}`, `+++ b/${filePath}`];
953
- for (const hunk of hunks) {
954
- lines.push(
955
- `@@ -${hunk.oldStart},${hunk.oldCount} +${hunk.newStart},${hunk.newCount} @@`
956
- );
957
- for (const edit of hunk.edits) {
958
- switch (edit.kind) {
959
- case "equal":
960
- lines.push(` ${edit.line}`);
961
- break;
962
- case "delete":
963
- lines.push(`-${edit.line}`);
964
- break;
965
- case "insert":
966
- lines.push(`+${edit.line}`);
967
- break;
968
- }
969
- }
970
- }
971
- return lines.join("\n");
972
- }
973
- function myersDiff(oldLines, newLines) {
974
- const n = oldLines.length;
975
- const m = newLines.length;
976
- if (n === 0 && m === 0) return [];
977
- if (n === 0)
978
- return newLines.map((line) => ({ kind: "insert", line }));
979
- if (m === 0)
980
- return oldLines.map((line) => ({ kind: "delete", line }));
981
- const max = n + m;
982
- const size = 2 * max + 1;
983
- const v = new Int32Array(size);
984
- const trace = [];
985
- const off = max;
986
- outer: for (let d = 0; d <= max; d++) {
987
- trace.push(v.slice());
988
- for (let k = -d; k <= d; k += 2) {
989
- let x2;
990
- if (k === -d || k !== d && v[k - 1 + off] < v[k + 1 + off]) {
991
- x2 = v[k + 1 + off];
992
- } else {
993
- x2 = v[k - 1 + off] + 1;
994
- }
995
- let y2 = x2 - k;
996
- while (x2 < n && y2 < m && oldLines[x2] === newLines[y2]) {
997
- x2++;
998
- y2++;
999
- }
1000
- v[k + off] = x2;
1001
- if (x2 >= n && y2 >= m) break outer;
1002
- }
1003
- }
1004
- let x = n;
1005
- let y = m;
1006
- const edits = [];
1007
- for (let d = trace.length - 1; d >= 0; d--) {
1008
- const tv = trace[d];
1009
- const k = x - y;
1010
- let prevK;
1011
- if (d === 0) {
1012
- while (x > 0 && y > 0) {
1013
- x--;
1014
- y--;
1015
- edits.push({ kind: "equal", line: oldLines[x] });
1016
- }
1017
- break;
1018
- }
1019
- if (k === -d || k !== d && tv[k - 1 + off] < tv[k + 1 + off]) {
1020
- prevK = k + 1;
1021
- } else {
1022
- prevK = k - 1;
1023
- }
1024
- const prevX = tv[prevK + off];
1025
- const prevY = prevX - prevK;
1026
- while (x > prevX && y > prevY) {
1027
- x--;
1028
- y--;
1029
- edits.push({ kind: "equal", line: oldLines[x] });
1030
- }
1031
- if (prevK === k + 1) {
1032
- y--;
1033
- edits.push({ kind: "insert", line: newLines[y] });
1034
- } else {
1035
- x--;
1036
- edits.push({ kind: "delete", line: oldLines[x] });
1037
- }
1038
- }
1039
- edits.reverse();
1040
- return edits;
1041
- }
1042
- function buildHunks(edits, contextLines) {
1043
- if (edits.length === 0) return [];
1044
- const changeIndices = [];
1045
- for (let i = 0; i < edits.length; i++) {
1046
- if (edits[i].kind !== "equal") {
1047
- changeIndices.push(i);
1048
- }
1049
- }
1050
- if (changeIndices.length === 0) return [];
1051
- const hunks = [];
1052
- let hunkStart = Math.max(0, changeIndices[0] - contextLines);
1053
- let hunkEnd = Math.min(edits.length - 1, changeIndices[0] + contextLines);
1054
- for (let i = 1; i < changeIndices.length; i++) {
1055
- const changeStart = changeIndices[i] - contextLines;
1056
- const changeEnd = Math.min(
1057
- edits.length - 1,
1058
- changeIndices[i] + contextLines
1059
- );
1060
- if (changeStart <= hunkEnd + 1) {
1061
- hunkEnd = changeEnd;
1062
- } else {
1063
- hunks.push(createHunk(edits, hunkStart, hunkEnd));
1064
- hunkStart = changeStart;
1065
- hunkEnd = changeEnd;
1066
- }
1067
- }
1068
- hunks.push(createHunk(edits, hunkStart, hunkEnd));
1069
- return hunks;
1070
- }
1071
- function createHunk(edits, start, end) {
1072
- const hunkEdits = edits.slice(start, end + 1);
1073
- let oldLine = 1;
1074
- let newLine = 1;
1075
- for (let i = 0; i < start; i++) {
1076
- if (edits[i].kind === "equal" || edits[i].kind === "delete") oldLine++;
1077
- if (edits[i].kind === "equal" || edits[i].kind === "insert") newLine++;
1078
- }
1079
- let oldCount = 0;
1080
- let newCount = 0;
1081
- for (const edit of hunkEdits) {
1082
- if (edit.kind === "equal" || edit.kind === "delete") oldCount++;
1083
- if (edit.kind === "equal" || edit.kind === "insert") newCount++;
1084
- }
1085
- return {
1086
- oldStart: oldLine,
1087
- oldCount,
1088
- newStart: newLine,
1089
- newCount,
1090
- edits: hunkEdits
1091
- };
1092
- }
1093
- var init_diff = __esm({
1094
- "src/vcs/diff.ts"() {
1095
- "use strict";
1096
- }
1097
- });
1098
-
1099
- // src/vcs/merge.ts
1100
- function threeWayMerge(base, ours, theirs, blobStore) {
1101
- const mergedFiles = /* @__PURE__ */ new Map();
1102
- const conflicts = [];
1103
- const allPaths = /* @__PURE__ */ new Set();
1104
- for (const [p, s] of base) if (!s.deleted) allPaths.add(p);
1105
- for (const [p, s] of ours) if (!s.deleted) allPaths.add(p);
1106
- for (const [p, s] of theirs) 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 path of allPaths) {
1110
- const b = base.get(path);
1111
- const o = ours.get(path);
1112
- const t = theirs.get(path);
1113
- const baseExists = b && !b.deleted;
1114
- const oursExists = o && !o.deleted;
1115
- const theirsExists = t && !t.deleted;
1116
- const baseHash = baseExists ? b.contentHash : void 0;
1117
- const oursHash = oursExists ? o.contentHash : void 0;
1118
- const theirsHash = theirsExists ? t.contentHash : void 0;
1119
- if (oursHash === theirsHash) {
1120
- continue;
1121
- }
1122
- if (theirsHash === baseHash && oursHash !== baseHash) {
1123
- if (!oursExists) {
1124
- mergedFiles.set(path, null);
1125
- }
1126
- continue;
1127
- }
1128
- if (oursHash === baseHash && theirsHash !== baseHash) {
1129
- if (!theirsExists) {
1130
- mergedFiles.set(path, null);
1131
- } else if (theirsHash && blobStore) {
1132
- const content = blobStore.get(theirsHash);
1133
- if (content) {
1134
- mergedFiles.set(path, content.toString("utf-8"));
1135
- }
1136
- }
1137
- continue;
1138
- }
1139
- if (!baseExists && oursExists && theirsExists) {
1140
- if (oursHash === theirsHash) {
1141
- continue;
1142
- }
1143
- const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : void 0;
1144
- const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : void 0;
1145
- if (oursContent !== void 0 && theirsContent !== void 0) {
1146
- const textResult = threeWayTextMerge("", oursContent, theirsContent);
1147
- if (textResult.clean) {
1148
- mergedFiles.set(path, textResult.merged);
1149
- continue;
1150
- }
1151
- conflicts.push({
1152
- path,
1153
- kind: "add-add",
1154
- ours: oursContent,
1155
- theirs: theirsContent,
1156
- mergedWithMarkers: textResult.merged
1157
- });
1158
- } else {
1159
- conflicts.push({ path, kind: "add-add", ours: oursContent, theirs: theirsContent });
1160
- }
1161
- continue;
1162
- }
1163
- if (oursExists && !theirsExists) {
1164
- conflicts.push({
1165
- path,
1166
- kind: "modify-delete",
1167
- ours: oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : void 0
1168
- });
1169
- continue;
1170
- }
1171
- if (!oursExists && theirsExists) {
1172
- conflicts.push({
1173
- path,
1174
- kind: "modify-delete",
1175
- theirs: theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : void 0
1176
- });
1177
- continue;
1178
- }
1179
- if (oursExists && theirsExists && oursHash !== theirsHash) {
1180
- const baseContent = baseHash && blobStore ? blobStore.get(baseHash)?.toString("utf-8") : void 0;
1181
- const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString("utf-8") : void 0;
1182
- const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString("utf-8") : void 0;
1183
- if (baseContent !== void 0 && oursContent !== void 0 && theirsContent !== void 0) {
1184
- const textResult = threeWayTextMerge(baseContent, oursContent, theirsContent);
1185
- if (textResult.clean) {
1186
- mergedFiles.set(path, textResult.merged);
1187
- } else {
1188
- conflicts.push({
1189
- path,
1190
- kind: "modify-modify",
1191
- base: baseContent,
1192
- ours: oursContent,
1193
- theirs: theirsContent,
1194
- mergedWithMarkers: textResult.merged
1195
- });
1196
- }
1197
- } else {
1198
- conflicts.push({
1199
- path,
1200
- kind: "modify-modify",
1201
- base: baseContent,
1202
- ours: oursContent,
1203
- theirs: theirsContent
1204
- });
1205
- }
1206
- continue;
1207
- }
1208
- }
1209
- const added = [...mergedFiles.values()].filter((v) => v !== null).length;
1210
- const deleted = [...mergedFiles.values()].filter((v) => v === null).length;
1211
- return {
1212
- clean: conflicts.length === 0,
1213
- mergedFiles,
1214
- conflicts,
1215
- stats: {
1216
- added,
1217
- modified: added,
1218
- // in a merge context, additions from theirs are "modified"
1219
- deleted,
1220
- conflicted: conflicts.length
1221
- }
1222
- };
1223
- }
1224
- function threeWayTextMerge(baseText, oursText, theirsText) {
1225
- const baseLines = baseText.split("\n");
1226
- const oursLines = oursText.split("\n");
1227
- const theirsLines = theirsText.split("\n");
1228
- const oursChanges = computeLineChanges(baseLines, oursLines);
1229
- const theirsChanges = computeLineChanges(baseLines, theirsLines);
1230
- const result = [];
1231
- let clean = true;
1232
- let baseIdx = 0;
1233
- let oursIdx = 0;
1234
- let theirsIdx = 0;
1235
- while (baseIdx < baseLines.length || oursIdx < oursLines.length || theirsIdx < theirsLines.length) {
1236
- const oursChange = oursChanges.get(baseIdx);
1237
- const theirsChange = theirsChanges.get(baseIdx);
1238
- if (baseIdx >= baseLines.length) {
1239
- while (oursIdx < oursLines.length) {
1240
- result.push(oursLines[oursIdx++]);
1241
- }
1242
- while (theirsIdx < theirsLines.length) {
1243
- result.push(theirsLines[theirsIdx++]);
1244
- }
1245
- break;
1246
- }
1247
- if (!oursChange && !theirsChange) {
1248
- result.push(baseLines[baseIdx]);
1249
- baseIdx++;
1250
- oursIdx++;
1251
- theirsIdx++;
1252
- } else if (oursChange && !theirsChange) {
1253
- applyChange(oursChange, result);
1254
- baseIdx += oursChange.baseCount;
1255
- oursIdx += oursChange.newCount;
1256
- theirsIdx += oursChange.baseCount;
1257
- } else if (!oursChange && theirsChange) {
1258
- applyChange(theirsChange, result);
1259
- baseIdx += theirsChange.baseCount;
1260
- oursIdx += theirsChange.baseCount;
1261
- theirsIdx += theirsChange.newCount;
1262
- } else if (oursChange && theirsChange) {
1263
- if (oursChange.baseCount === theirsChange.baseCount && oursChange.newLines.join("\n") === theirsChange.newLines.join("\n")) {
1264
- applyChange(oursChange, result);
1265
- baseIdx += oursChange.baseCount;
1266
- oursIdx += oursChange.newCount;
1267
- theirsIdx += theirsChange.newCount;
1268
- } else {
1269
- clean = false;
1270
- result.push("<<<<<<< ours");
1271
- for (const line of oursChange.newLines) result.push(line);
1272
- result.push("=======");
1273
- for (const line of theirsChange.newLines) result.push(line);
1274
- result.push(">>>>>>> theirs");
1275
- baseIdx += Math.max(oursChange.baseCount, theirsChange.baseCount);
1276
- oursIdx += oursChange.newCount;
1277
- theirsIdx += theirsChange.newCount;
1278
- }
1279
- }
1280
- }
1281
- return { clean, merged: result.join("\n") };
1282
- }
1283
- function applyChange(change, result) {
1284
- for (const line of change.newLines) {
1285
- result.push(line);
1286
- }
1287
- }
1288
- function computeLineChanges(baseLines, newLines) {
1289
- const changes = /* @__PURE__ */ new Map();
1290
- const matches = lcsMatch(baseLines, newLines);
1291
- let baseIdx = 0;
1292
- let newIdx = 0;
1293
- for (const match of matches) {
1294
- if (baseIdx < match.baseIdx || newIdx < match.newIdx) {
1295
- const baseCount = match.baseIdx - baseIdx;
1296
- const newCount = match.newIdx - newIdx;
1297
- if (baseCount > 0 || newCount > 0) {
1298
- changes.set(baseIdx, {
1299
- baseStart: baseIdx,
1300
- baseCount,
1301
- newCount,
1302
- newLines: newLines.slice(newIdx, newIdx + newCount)
1303
- });
1304
- }
1305
- }
1306
- baseIdx = match.baseIdx + 1;
1307
- newIdx = match.newIdx + 1;
1308
- }
1309
- if (baseIdx < baseLines.length || newIdx < newLines.length) {
1310
- const baseCount = baseLines.length - baseIdx;
1311
- const newCount = newLines.length - newIdx;
1312
- if (baseCount > 0 || newCount > 0) {
1313
- changes.set(baseIdx, {
1314
- baseStart: baseIdx,
1315
- baseCount,
1316
- newCount,
1317
- newLines: newLines.slice(newIdx)
1318
- });
1319
- }
1320
- }
1321
- return changes;
1322
- }
1323
- function lcsMatch(a, b) {
1324
- const n = a.length;
1325
- const m = b.length;
1326
- if (n === 0 || m === 0) return [];
1327
- const dp = Array.from(
1328
- { length: n + 1 },
1329
- () => new Array(m + 1).fill(0)
1330
- );
1331
- for (let i2 = 1; i2 <= n; i2++) {
1332
- for (let j2 = 1; j2 <= m; j2++) {
1333
- if (a[i2 - 1] === b[j2 - 1]) {
1334
- dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
1335
- } else {
1336
- dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
1337
- }
1338
- }
1339
- }
1340
- const matches = [];
1341
- let i = n;
1342
- let j = m;
1343
- while (i > 0 && j > 0) {
1344
- if (a[i - 1] === b[j - 1]) {
1345
- matches.unshift({ baseIdx: i - 1, newIdx: j - 1 });
1346
- i--;
1347
- j--;
1348
- } else if (dp[i - 1][j] > dp[i][j - 1]) {
1349
- i--;
1350
- } else {
1351
- j--;
1352
- }
1353
- }
1354
- return matches;
1355
- }
1356
- var init_merge = __esm({
1357
- "src/vcs/merge.ts"() {
1358
- "use strict";
1359
- }
1360
- });
1361
-
1362
- // src/vcs/issue.ts
1363
- import { exec } from "child_process";
1364
- import { promisify } from "util";
1365
- import {
1366
- existsSync as existsSync3,
1367
- readFileSync as readFileSync3,
1368
- writeFileSync as writeFileSync3,
1369
- mkdirSync as mkdirSync2,
1370
- openSync,
1371
- closeSync,
1372
- unlinkSync
1373
- } from "fs";
1374
- import { join as join3, dirname as dirname2 } from "path";
1375
- function getIssueCounterPath(rootPath) {
1376
- return join3(rootPath, ".trellis", "issue-counter.json");
1377
- }
1378
- function nextIssueId(rootPath) {
1379
- const counterPath = getIssueCounterPath(rootPath);
1380
- const dir = dirname2(counterPath);
1381
- if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
1382
- const lockPath = `${counterPath}.lock`;
1383
- const deadline = Date.now() + 5e3;
1384
- let lockFd;
1385
- while (Date.now() < deadline) {
1386
- try {
1387
- lockFd = openSync(lockPath, "wx");
1388
- break;
1389
- } catch (err) {
1390
- if (err?.code !== "EEXIST") {
1391
- throw err;
1392
- }
1393
- }
1394
- }
1395
- if (lockFd === void 0) {
1396
- throw new Error(
1397
- `Timed out waiting for issue counter lock: ${lockPath}. Another Trellis process may be stalled.`
1398
- );
1399
- }
1400
- try {
1401
- let counter = 0;
1402
- if (existsSync3(counterPath)) {
1403
- try {
1404
- counter = JSON.parse(readFileSync3(counterPath, "utf-8")).counter ?? 0;
1405
- } catch {
1406
- }
1407
- }
1408
- counter++;
1409
- writeFileSync3(counterPath, JSON.stringify({ counter }, null, 2));
1410
- return `TRL-${counter}`;
1411
- } finally {
1412
- closeSync(lockFd);
1413
- try {
1414
- unlinkSync(lockPath);
1415
- } catch {
1416
- }
1417
- }
1418
- }
1419
- function getIssueFact(ctx, entityId, attr) {
1420
- const facts = ctx.store.getFactsByEntity(entityId);
1421
- const matches = facts.filter((f) => f.a === attr);
1422
- return matches.length > 0 ? matches[matches.length - 1].v : void 0;
1423
- }
1424
- function getIssueLinks(ctx, entityId, attr) {
1425
- const links = ctx.store.getLinksByEntity(entityId);
1426
- return links.filter((l) => l.a === attr && l.e1 === entityId).map((l) => l.e2);
1427
- }
1428
- function getCriteriaForIssue(ctx, issueId) {
1429
- const eid = issueEntityId(issueId);
1430
- const criterionLinks = ctx.store.getLinksByAttribute("criterionOf").filter((l) => l.e2 === eid);
1431
- return criterionLinks.map((link) => {
1432
- const ceid = link.e1;
1433
- const facts = ctx.store.getFactsByEntity(ceid);
1434
- const getLast = (a) => {
1435
- const matches = facts.filter((f) => f.a === a);
1436
- return matches.length > 0 ? matches[matches.length - 1].v : void 0;
1437
- };
1438
- return {
1439
- id: ceid,
1440
- description: getLast("description"),
1441
- command: getLast("command"),
1442
- status: getLast("status"),
1443
- lastRunAt: getLast("lastRunAt"),
1444
- lastOutput: getLast("lastOutput")
1445
- };
1446
- });
1447
- }
1448
- function buildIssueInfo(ctx, entityId) {
1449
- const facts = ctx.store.getFactsByEntity(entityId);
1450
- const get = (a) => {
1451
- const matches = facts.filter((f) => f.a === a);
1452
- return matches.length > 0 ? matches[matches.length - 1].v : void 0;
1453
- };
1454
- const labelsStr = get("labels");
1455
- const labels = labelsStr ? labelsStr.split(",").filter(Boolean) : [];
1456
- const trackedOnLinks = getIssueLinks(ctx, entityId, "trackedOn");
1457
- const branchName = trackedOnLinks.length > 0 ? trackedOnLinks[0].replace(/^branch:/, "") : void 0;
1458
- const childOfLinks = getIssueLinks(ctx, entityId, "childOf");
1459
- const parentId = childOfLinks.length > 0 ? childOfLinks[0].replace(/^issue:/, "") : void 0;
1460
- const bareId = entityId.replace(/^issue:/, "");
1461
- const blockedByLinks = getIssueLinks(ctx, entityId, "blockedBy");
1462
- const blockedBy = blockedByLinks.map((e) => e.replace(/^issue:/, ""));
1463
- const allBlockedByLinks = ctx.store.getLinksByAttribute("blockedBy");
1464
- const blocking = allBlockedByLinks.filter((l) => l.e2 === entityId).map((l) => l.e1.replace(/^issue:/, ""));
1465
- const isBlocked = blockedByLinks.some((blockerEid) => {
1466
- const blockerStatus = getIssueFact(ctx, blockerEid, "status");
1467
- return blockerStatus !== "closed";
1468
- });
1469
- return {
1470
- id: bareId,
1471
- title: get("title"),
1472
- description: get("description"),
1473
- status: get("status"),
1474
- priority: get("priority"),
1475
- labels,
1476
- assignee: get("assignee"),
1477
- createdAt: get("createdAt"),
1478
- createdBy: get("createdBy"),
1479
- startedAt: get("startedAt"),
1480
- pausedAt: get("pausedAt"),
1481
- pauseNote: get("pauseNote") || void 0,
1482
- closedAt: get("closedAt"),
1483
- parentId,
1484
- branchName,
1485
- blockedBy,
1486
- blocking,
1487
- isBlocked,
1488
- criteria: getCriteriaForIssue(ctx, bareId)
1489
- };
1490
- }
1491
- async function createIssue(ctx, rootPath, title, opts) {
1492
- const id = nextIssueId(rootPath);
1493
- const op = await createVcsOp("vcs:issueCreate", {
1494
- agentId: ctx.agentId,
1495
- previousHash: ctx.getLastOp()?.hash,
1496
- vcs: {
1497
- issueId: id,
1498
- issueTitle: title,
1499
- issueDescription: opts?.description,
1500
- issueStatus: opts?.status ?? "backlog",
1501
- issuePriority: opts?.priority ?? "medium",
1502
- issueLabels: opts?.labels,
1503
- issueAssignee: opts?.assignee,
1504
- parentIssueId: opts?.parentId
1505
- }
1506
- });
1507
- await ctx.applyOp(op);
1508
- if (opts?.criteria) {
1509
- for (let i = 0; i < opts.criteria.length; i++) {
1510
- await addCriterion(
1511
- ctx,
1512
- id,
1513
- opts.criteria[i].description,
1514
- opts.criteria[i].command
1515
- );
1516
- }
1517
- }
1518
- return op;
1519
- }
1520
- async function updateIssue(ctx, id, updates) {
1521
- const issue = getIssue(ctx, id);
1522
- if (!issue) {
1523
- throw new Error(`Issue ${id} not found.`);
1524
- }
1525
- const vcs = { issueId: id };
1526
- if (updates.title !== void 0) vcs.issueTitle = updates.title;
1527
- if (updates.description !== void 0) vcs.issueDescription = updates.description;
1528
- if (updates.status !== void 0) {
1529
- vcs.oldIssueStatus = getIssueFact(ctx, issueEntityId(id), "status");
1530
- vcs.issueStatus = updates.status;
1531
- }
1532
- if (updates.priority !== void 0) vcs.issuePriority = updates.priority;
1533
- if (updates.labels !== void 0) vcs.issueLabels = updates.labels;
1534
- if (updates.assignee !== void 0) vcs.issueAssignee = updates.assignee;
1535
- if (updates.parentId !== void 0) {
1536
- const newParent = updates.parentId;
1537
- if (newParent === id) {
1538
- throw new Error(`Issue ${id} cannot be its own parent.`);
1539
- }
1540
- if (newParent) {
1541
- const parent = getIssue(ctx, newParent);
1542
- if (!parent) {
1543
- throw new Error(`Parent issue ${newParent} not found.`);
1544
- }
1545
- }
1546
- const currentParent = issue.parentId;
1547
- if (newParent !== currentParent) {
1548
- if (currentParent) vcs.oldParentIssueId = currentParent;
1549
- if (newParent) vcs.parentIssueId = newParent;
1550
- }
1551
- }
1552
- const op = await createVcsOp("vcs:issueUpdate", {
1553
- agentId: ctx.agentId,
1554
- previousHash: ctx.getLastOp()?.hash,
1555
- vcs
1556
- });
1557
- await ctx.applyOp(op);
1558
- return op;
1559
- }
1560
- async function startIssue(ctx, id, branchName) {
1561
- const eid = issueEntityId(id);
1562
- const status = getIssueFact(ctx, eid, "status");
1563
- if (status === "closed") {
1564
- throw new Error(`Cannot start closed issue ${id}. Reopen it first.`);
1565
- }
1566
- if (status === "in_progress") {
1567
- throw new Error(`Issue ${id} is already in progress.`);
1568
- }
1569
- const op = await createVcsOp("vcs:issueStart", {
1570
- agentId: ctx.agentId,
1571
- previousHash: ctx.getLastOp()?.hash,
1572
- vcs: {
1573
- issueId: id,
1574
- oldIssueStatus: status,
1575
- issueAssignee: ctx.agentId,
1576
- branchName
1577
- }
1578
- });
1579
- await ctx.applyOp(op);
1580
- return op;
1581
- }
1582
- async function pauseIssue(ctx, id, note) {
1583
- if (!note || !note.trim()) {
1584
- throw new Error(
1585
- `A pause note is required. Explain why the issue is paused and what must happen before resuming.`
1586
- );
1587
- }
1588
- const eid = issueEntityId(id);
1589
- const status = getIssueFact(ctx, eid, "status");
1590
- if (status !== "in_progress") {
1591
- throw new Error(
1592
- `Cannot pause issue ${id} \u2014 status is '${status}', expected 'in_progress'.`
1593
- );
1594
- }
1595
- const op = await createVcsOp("vcs:issuePause", {
1596
- agentId: ctx.agentId,
1597
- previousHash: ctx.getLastOp()?.hash,
1598
- vcs: {
1599
- issueId: id,
1600
- oldIssueStatus: status,
1601
- pauseNote: note.trim()
1602
- }
1603
- });
1604
- await ctx.applyOp(op);
1605
- return op;
1606
- }
1607
- async function resumeIssue(ctx, id) {
1608
- const eid = issueEntityId(id);
1609
- const status = getIssueFact(ctx, eid, "status");
1610
- if (status !== "paused") {
1611
- throw new Error(
1612
- `Cannot resume issue ${id} \u2014 status is '${status}', expected 'paused'.`
1613
- );
1614
- }
1615
- const op = await createVcsOp("vcs:issueResume", {
1616
- agentId: ctx.agentId,
1617
- previousHash: ctx.getLastOp()?.hash,
1618
- vcs: { issueId: id, oldIssueStatus: status }
1619
- });
1620
- await ctx.applyOp(op);
1621
- return op;
1622
- }
1623
- async function closeIssue(ctx, id, opts) {
1624
- const eid = issueEntityId(id);
1625
- const status = getIssueFact(ctx, eid, "status");
1626
- if (status === "closed") {
1627
- throw new Error(`Issue ${id} is already closed.`);
1628
- }
1629
- const criteria = getCriteriaForIssue(ctx, id);
1630
- const results = criteria.map((c) => ({
1631
- id: c.id,
1632
- description: c.description,
1633
- command: c.command,
1634
- status: c.status ?? "pending"
1635
- }));
1636
- const allPassed = results.length === 0 || results.every((r) => r.status === "passed");
1637
- if (!allPassed) {
1638
- const failing = results.filter((r) => r.status !== "passed");
1639
- throw new Error(
1640
- `Cannot close issue ${id}: ${failing.length} criteria not passing:
1641
- ` + failing.map((f) => ` - ${f.description ?? f.id} (${f.status})`).join("\n")
1642
- );
1643
- }
1644
- if (!opts?.confirm) {
1645
- return { criteriaResults: results };
1646
- }
1647
- const startedAt = getIssueFact(ctx, eid, "startedAt");
1648
- const op = await createVcsOp("vcs:issueClose", {
1649
- agentId: ctx.agentId,
1650
- previousHash: ctx.getLastOp()?.hash,
1651
- vcs: { issueId: id, oldIssueStatus: status }
1652
- });
1653
- await ctx.applyOp(op);
1654
- if (startedAt) {
1655
- const durationMs = Date.now() - new Date(startedAt).getTime();
1656
- ctx.store.addFacts([{ e: eid, a: "durationMs", v: durationMs }]);
1657
- }
1658
- return { op, criteriaResults: results };
1659
- }
1660
- async function triageIssue(ctx, id) {
1661
- const eid = issueEntityId(id);
1662
- const status = getIssueFact(ctx, eid, "status");
1663
- if (status !== "backlog") {
1664
- throw new Error(
1665
- `Cannot triage issue ${id} \u2014 status is '${status}', expected 'backlog'.`
1666
- );
1667
- }
1668
- const op = await createVcsOp("vcs:issueUpdate", {
1669
- agentId: ctx.agentId,
1670
- previousHash: ctx.getLastOp()?.hash,
1671
- vcs: {
1672
- issueId: id,
1673
- oldIssueStatus: status,
1674
- issueStatus: "queue"
1675
- }
1676
- });
1677
- await ctx.applyOp(op);
1678
- return op;
1679
- }
1680
- async function reopenIssue(ctx, id) {
1681
- const eid = issueEntityId(id);
1682
- const status = getIssueFact(ctx, eid, "status");
1683
- if (status !== "closed") {
1684
- throw new Error(
1685
- `Cannot reopen issue ${id} \u2014 status is '${status}', expected 'closed'.`
1686
- );
1687
- }
1688
- const op = await createVcsOp("vcs:issueReopen", {
1689
- agentId: ctx.agentId,
1690
- previousHash: ctx.getLastOp()?.hash,
1691
- vcs: { issueId: id, oldIssueStatus: status }
1692
- });
1693
- await ctx.applyOp(op);
1694
- return op;
1695
- }
1696
- async function assignIssue(ctx, id, agentId) {
1697
- return updateIssue(ctx, id, { assignee: agentId });
1698
- }
1699
- async function blockIssue(ctx, id, blockedById) {
1700
- const eid = issueEntityId(id);
1701
- const blockerEid = issueEntityId(blockedById);
1702
- if (!getIssueFact(ctx, eid, "type")) {
1703
- throw new Error(`Issue ${id} not found.`);
1704
- }
1705
- if (!getIssueFact(ctx, blockerEid, "type")) {
1706
- throw new Error(`Blocking issue ${blockedById} not found.`);
1707
- }
1708
- if (id === blockedById) {
1709
- throw new Error(`Issue cannot block itself.`);
1710
- }
1711
- const op = await createVcsOp("vcs:issueBlock", {
1712
- agentId: ctx.agentId,
1713
- previousHash: ctx.getLastOp()?.hash,
1714
- vcs: { issueId: id, blockedByIssueId: blockedById }
1715
- });
1716
- await ctx.applyOp(op);
1717
- return op;
1718
- }
1719
- async function unblockIssue(ctx, id, blockedById) {
1720
- const op = await createVcsOp("vcs:issueUnblock", {
1721
- agentId: ctx.agentId,
1722
- previousHash: ctx.getLastOp()?.hash,
1723
- vcs: { issueId: id, blockedByIssueId: blockedById }
1724
- });
1725
- await ctx.applyOp(op);
1726
- return op;
1727
- }
1728
- async function addCriterion(ctx, issueId, description, command) {
1729
- const existing = getCriteriaForIssue(ctx, issueId);
1730
- const index = existing.length + 1;
1731
- const cid = criterionEntityId(issueId, index);
1732
- const op = await createVcsOp("vcs:criterionAdd", {
1733
- agentId: ctx.agentId,
1734
- previousHash: ctx.getLastOp()?.hash,
1735
- vcs: {
1736
- issueId,
1737
- criterionId: cid,
1738
- criterionDescription: description,
1739
- criterionCommand: command
1740
- }
1741
- });
1742
- await ctx.applyOp(op);
1743
- return op;
1744
- }
1745
- async function setCriterionStatus(ctx, issueId, criterionIndex, status) {
1746
- const criteria = getCriteriaForIssue(ctx, issueId);
1747
- if (criterionIndex < 1 || criterionIndex > criteria.length) {
1748
- throw new Error(
1749
- `Criterion index ${criterionIndex} out of range (1\u2013${criteria.length})`
1750
- );
1751
- }
1752
- const c = criteria[criterionIndex - 1];
1753
- const op = await createVcsOp("vcs:criterionUpdate", {
1754
- agentId: ctx.agentId,
1755
- previousHash: ctx.getLastOp()?.hash,
1756
- vcs: {
1757
- issueId,
1758
- criterionId: c.id,
1759
- criterionStatus: status
1760
- }
1761
- });
1762
- await ctx.applyOp(op);
1763
- return op;
1764
- }
1765
- async function runCriteria(ctx, issueId, rootPath) {
1766
- const criteria = getCriteriaForIssue(ctx, issueId);
1767
- const results = [];
1768
- for (const c of criteria) {
1769
- if (!c.command) {
1770
- results.push({
1771
- id: c.id,
1772
- description: c.description,
1773
- status: c.status ?? "skipped"
1774
- });
1775
- continue;
1776
- }
1777
- let status = "failed";
1778
- let output = "";
1779
- let exitCode = 1;
1780
- try {
1781
- const result = await execAsync(c.command, {
1782
- cwd: rootPath,
1783
- timeout: 12e4
1784
- });
1785
- output = (result.stdout + "\n" + result.stderr).trim();
1786
- exitCode = 0;
1787
- status = "passed";
1788
- } catch (err) {
1789
- output = (err.stdout ?? "") + "\n" + (err.stderr ?? err.message ?? "");
1790
- output = output.trim();
1791
- exitCode = err.code ?? 1;
1792
- status = "failed";
1793
- }
1794
- const updateOp = await createVcsOp("vcs:criterionUpdate", {
1795
- agentId: ctx.agentId,
1796
- previousHash: ctx.getLastOp()?.hash,
1797
- vcs: {
1798
- criterionId: c.id,
1799
- criterionStatus: status,
1800
- criterionOutput: output.slice(0, 4096)
1801
- }
1802
- });
1803
- await ctx.applyOp(updateOp);
1804
- results.push({
1805
- id: c.id,
1806
- description: c.description,
1807
- command: c.command,
1808
- status,
1809
- output,
1810
- exitCode
1811
- });
1812
- }
1813
- return results;
1814
- }
1815
- function listIssues(ctx, filters) {
1816
- const issueFacts = ctx.store.getFactsByAttribute("type").filter((f) => f.v === "Issue");
1817
- let issues = issueFacts.map((f) => buildIssueInfo(ctx, f.e));
1818
- if (filters?.status) {
1819
- issues = issues.filter((i) => i.status === filters.status);
1820
- }
1821
- if (filters?.assignee) {
1822
- issues = issues.filter((i) => i.assignee === filters.assignee);
1823
- }
1824
- if (filters?.label) {
1825
- issues = issues.filter((i) => i.labels.includes(filters.label));
1826
- }
1827
- if (filters?.parentId) {
1828
- issues = issues.filter((i) => i.parentId === filters.parentId);
1829
- }
1830
- if (filters?.blocked !== void 0) {
1831
- issues = issues.filter((i) => i.isBlocked === filters.blocked);
1832
- }
1833
- return issues;
1834
- }
1835
- function getIssue(ctx, id) {
1836
- const eid = issueEntityId(id);
1837
- const typeFact = ctx.store.getFactsByEntity(eid).find((f) => f.a === "type" && f.v === "Issue");
1838
- if (!typeFact) return null;
1839
- return buildIssueInfo(ctx, eid);
1840
- }
1841
- function getActiveIssues(ctx) {
1842
- return listIssues(ctx, { status: "in_progress" });
1843
- }
1844
- function checkCompletionReadiness(ctx) {
1845
- const all = listIssues(ctx);
1846
- const queue = all.filter((i) => i.status === "queue");
1847
- const paused = all.filter((i) => i.status === "paused");
1848
- const inProgress = all.filter((i) => i.status === "in_progress");
1849
- const ready = queue.length === 0 && paused.length === 0 && inProgress.length === 0;
1850
- const parts = [];
1851
- if (ready) {
1852
- parts.push("\u2713 All clear \u2014 no queue, paused, or in-progress issues.");
1853
- } else {
1854
- parts.push("\u2717 Not ready for completion:");
1855
- if (queue.length > 0) {
1856
- parts.push(
1857
- ` Queue (${queue.length}): ${queue.map((i) => i.id).join(", ")}`
1858
- );
1859
- }
1860
- if (inProgress.length > 0) {
1861
- parts.push(
1862
- ` In progress (${inProgress.length}): ${inProgress.map((i) => i.id).join(", ")}`
1863
- );
1864
- }
1865
- if (paused.length > 0) {
1866
- parts.push(
1867
- ` Paused (${paused.length}): ${paused.map((i) => `${i.id}${i.pauseNote ? ` \u2014 ${i.pauseNote}` : ""}`).join(", ")}`
1868
- );
1869
- }
1870
- }
1871
- return { ready, queue, paused, inProgress, summary: parts.join("\n") };
1872
- }
1873
- var execAsync;
1874
- var init_issue = __esm({
1875
- "src/vcs/issue.ts"() {
1876
- "use strict";
1877
- init_ops();
1878
- init_types();
1879
- execAsync = promisify(exec);
1880
- }
1881
- });
1882
-
1883
- // src/vcs/op-log.ts
1884
- import {
1885
- existsSync as existsSync4,
1886
- mkdirSync as mkdirSync3,
1887
- readFileSync as readFileSync4,
1888
- writeFileSync as writeFileSync4,
1889
- copyFileSync,
1890
- openSync as openSync2,
1891
- closeSync as closeSync2,
1892
- unlinkSync as unlinkSync2,
1893
- renameSync
1894
- } from "fs";
1895
- import { dirname as dirname3 } from "path";
1896
- function lockTimeoutMs() {
1897
- const raw = process.env.TRELLIS_OPLOG_LOCK_MS;
1898
- if (!raw) return 5e3;
1899
- const parsed = Number(raw);
1900
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 5e3;
1901
- }
1902
- var JsonOpLog, LaneOpLog;
1903
- var init_op_log = __esm({
1904
- "src/vcs/op-log.ts"() {
1905
- "use strict";
1906
- JsonOpLog = class {
1907
- ops = [];
1908
- filePath;
1909
- lockPath;
1910
- constructor(filePath) {
1911
- this.filePath = filePath;
1912
- this.lockPath = `${filePath}.lock`;
1913
- }
1914
- get path() {
1915
- return this.filePath;
1916
- }
1917
- load() {
1918
- if (existsSync4(this.filePath)) {
1919
- const raw = readFileSync4(this.filePath, "utf-8");
1920
- try {
1921
- this.ops = JSON.parse(raw);
1922
- } catch {
1923
- const backupPath = this.filePath + ".bak";
1924
- if (existsSync4(backupPath)) {
1925
- const backupRaw = readFileSync4(backupPath, "utf-8");
1926
- this.ops = JSON.parse(backupRaw);
1927
- writeFileSync4(this.filePath, backupRaw);
1928
- } else {
1929
- throw new Error(
1930
- `Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`
1931
- );
1932
- }
1933
- }
1934
- }
1935
- }
1936
- append(op) {
1937
- this.withLock(() => {
1938
- const diskOps = this.readOpsFromDisk();
1939
- this.ops = diskOps;
1940
- if (this.ops.some((existing) => existing.hash === op.hash)) {
1941
- return;
1942
- }
1943
- this.ops.push(op);
1944
- this.flush();
1945
- });
1946
- }
1947
- readAll() {
1948
- return [...this.ops];
1949
- }
1950
- getLastOp() {
1951
- return this.ops.length > 0 ? this.ops[this.ops.length - 1] : void 0;
1952
- }
1953
- count() {
1954
- return this.ops.length;
1955
- }
1956
- flush() {
1957
- const dir = dirname3(this.filePath);
1958
- if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
1959
- if (existsSync4(this.filePath)) {
1960
- const backupPath = this.filePath + ".bak";
1961
- try {
1962
- copyFileSync(this.filePath, backupPath);
1963
- } catch {
1964
- }
1965
- }
1966
- const tempPath = `${this.filePath}.tmp`;
1967
- writeFileSync4(tempPath, JSON.stringify(this.ops, null, 2));
1968
- renameSync(tempPath, this.filePath);
1969
- }
1970
- readOpsFromDisk() {
1971
- if (!existsSync4(this.filePath)) {
1972
- return [];
1973
- }
1974
- const raw = readFileSync4(this.filePath, "utf-8");
1975
- try {
1976
- const parsed = JSON.parse(raw);
1977
- return Array.isArray(parsed) ? parsed : [];
1978
- } catch {
1979
- const backupPath = this.filePath + ".bak";
1980
- if (existsSync4(backupPath)) {
1981
- const backupRaw = readFileSync4(backupPath, "utf-8");
1982
- const parsedBackup = JSON.parse(backupRaw);
1983
- writeFileSync4(this.filePath, backupRaw);
1984
- return Array.isArray(parsedBackup) ? parsedBackup : [];
1985
- }
1986
- throw new Error(
1987
- `Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`
1988
- );
1989
- }
1990
- }
1991
- withLock(fn) {
1992
- const dir = dirname3(this.filePath);
1993
- if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
1994
- const deadline = Date.now() + lockTimeoutMs();
1995
- let lockFd;
1996
- while (Date.now() < deadline) {
1997
- try {
1998
- lockFd = openSync2(this.lockPath, "wx");
1999
- break;
2000
- } catch (err) {
2001
- if (err?.code !== "EEXIST") {
2002
- throw err;
2003
- }
2004
- }
2005
- }
2006
- if (lockFd === void 0) {
2007
- throw new Error(
2008
- `Timed out waiting for ops log lock: ${this.lockPath}. Another Trellis process may be stalled.`
2009
- );
2010
- }
2011
- try {
2012
- fn();
2013
- } finally {
2014
- closeSync2(lockFd);
2015
- try {
2016
- unlinkSync2(this.lockPath);
2017
- } catch {
2018
- }
2019
- }
2020
- }
2021
- static repair(filePath) {
2022
- if (!existsSync4(filePath)) {
2023
- return { recovered: 0, lost: 0 };
2024
- }
2025
- const raw = readFileSync4(filePath, "utf-8");
2026
- try {
2027
- const ops = JSON.parse(raw);
2028
- return { recovered: ops.length, lost: 0 };
2029
- } catch {
2030
- }
2031
- const lastHash = raw.lastIndexOf('"hash": "trellis:op:');
2032
- if (lastHash === -1) {
2033
- const bakPath = filePath + ".bak";
2034
- if (existsSync4(bakPath)) {
2035
- const bakRaw = readFileSync4(bakPath, "utf-8");
2036
- try {
2037
- const ops = JSON.parse(bakRaw);
2038
- writeFileSync4(filePath, bakRaw);
2039
- return { recovered: ops.length, lost: 0 };
2040
- } catch {
2041
- }
2042
- }
2043
- writeFileSync4(filePath, "[]");
2044
- return { recovered: 0, lost: -1 };
2045
- }
2046
- const endOfLine = raw.indexOf("\n", lastHash);
2047
- const closingBrace = raw.indexOf(" }", endOfLine);
2048
- if (closingBrace === -1) {
2049
- writeFileSync4(filePath, "[]");
2050
- return { recovered: 0, lost: -1 };
2051
- }
2052
- const fixed = raw.slice(0, closingBrace + 3) + "\n]";
2053
- try {
2054
- const ops = JSON.parse(fixed);
2055
- writeFileSync4(filePath + ".corrupted", raw);
2056
- writeFileSync4(filePath, fixed);
2057
- return { recovered: ops.length, lost: 0 };
2058
- } catch {
2059
- writeFileSync4(filePath + ".corrupted", raw);
2060
- writeFileSync4(filePath, "[]");
2061
- return { recovered: 0, lost: -1 };
2062
- }
2063
- }
2064
- };
2065
- LaneOpLog = class extends JsonOpLog {
2066
- constructor(laneDir2) {
2067
- super(`${laneDir2}/ops.json`);
2068
- }
2069
- };
2070
- }
2071
- });
2072
-
2073
- // src/vcs/lane.ts
2074
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync5, readdirSync } from "fs";
2075
- import { join as join4 } from "path";
2076
- import { randomUUID } from "crypto";
2077
- function lanesRoot(trellisDir) {
2078
- return join4(trellisDir, "lanes");
2079
- }
2080
- function laneDir(trellisDir, laneId) {
2081
- return join4(lanesRoot(trellisDir), laneId);
2082
- }
2083
- function laneMetaPath(trellisDir, laneId) {
2084
- return join4(laneDir(trellisDir, laneId), "meta.json");
2085
- }
2086
- function newLaneId() {
2087
- return `lane-${randomUUID()}`;
2088
- }
2089
- function loadLaneMeta(trellisDir, laneId) {
2090
- const path = laneMetaPath(trellisDir, laneId);
2091
- if (!existsSync5(path)) return void 0;
2092
- return JSON.parse(readFileSync5(path, "utf-8"));
2093
- }
2094
- function saveLaneMeta(trellisDir, meta) {
2095
- const dir = laneDir(trellisDir, meta.id);
2096
- if (!existsSync5(dir)) mkdirSync4(dir, { recursive: true });
2097
- writeFileSync5(
2098
- laneMetaPath(trellisDir, meta.id),
2099
- JSON.stringify(meta, null, 2) + "\n"
2100
- );
2101
- }
2102
- function listLaneIds(trellisDir) {
2103
- const root = lanesRoot(trellisDir);
2104
- if (!existsSync5(root)) return [];
2105
- return readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("lane-")).map((d) => d.name);
2106
- }
2107
- function resolveLaneHeadFromJournal(meta, laneOps) {
2108
- return laneOps.at(-1)?.hash ?? meta.headOpHash ?? meta.baseOpHash;
2109
- }
2110
- function createLaneMeta(trellisDir, params) {
2111
- const now = (/* @__PURE__ */ new Date()).toISOString();
2112
- const meta = {
2113
- id: newLaneId(),
2114
- status: "active",
2115
- baseBranch: params.baseBranch,
2116
- baseOpHash: params.baseOpHash,
2117
- targetBranch: params.targetBranch ?? params.baseBranch,
2118
- headOpHash: params.baseOpHash,
2119
- agentId: params.agentId,
2120
- issueId: params.issueId,
2121
- sessionId: params.sessionId,
2122
- parentLaneId: params.parentLaneId,
2123
- forkKind: params.forkKind,
2124
- forkedAt: params.forkedAt,
2125
- virtualBaseOpHash: params.virtualBaseOpHash,
2126
- worktreePath: params.worktreePath,
2127
- leaseExpiresAt: params.leaseExpiresAt,
2128
- createdAt: now,
2129
- updatedAt: now
2130
- };
2131
- saveLaneMeta(trellisDir, meta);
2132
- return meta;
2133
- }
2134
- function updateLaneHead(trellisDir, laneId, headOpHash) {
2135
- const meta = loadLaneMeta(trellisDir, laneId);
2136
- if (!meta) return;
2137
- meta.headOpHash = headOpHash;
2138
- meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2139
- saveLaneMeta(trellisDir, meta);
2140
- }
2141
- function listLaneMetas(trellisDir) {
2142
- return listLaneIds(trellisDir).map((id) => loadLaneMeta(trellisDir, id)).filter((m) => m !== void 0);
2143
- }
2144
- var init_lane = __esm({
2145
- "src/vcs/lane.ts"() {
2146
- "use strict";
2147
- }
2148
- });
2149
-
2150
- export {
2151
- decompose,
2152
- init_decompose,
2153
- BlobStore,
2154
- init_blob_store,
2155
- shouldAdvanceBranchHead,
2156
- getBranchHeadOpHash,
2157
- createBranch,
2158
- switchBranch,
2159
- listBranches,
2160
- deleteBranch,
2161
- saveBranchState,
2162
- loadBranchState,
2163
- init_branch,
2164
- createMilestone,
2165
- listMilestones,
2166
- init_milestone,
2167
- createCheckpoint,
2168
- listCheckpoints,
2169
- init_checkpoint,
2170
- diffFileStates,
2171
- buildFileStateAtOp,
2172
- diffOpRange,
2173
- generateUnifiedDiff,
2174
- myersDiff,
2175
- init_diff,
2176
- threeWayMerge,
2177
- threeWayTextMerge,
2178
- init_merge,
2179
- createIssue,
2180
- updateIssue,
2181
- startIssue,
2182
- pauseIssue,
2183
- resumeIssue,
2184
- closeIssue,
2185
- triageIssue,
2186
- reopenIssue,
2187
- assignIssue,
2188
- blockIssue,
2189
- unblockIssue,
2190
- addCriterion,
2191
- setCriterionStatus,
2192
- runCriteria,
2193
- listIssues,
2194
- getIssue,
2195
- getActiveIssues,
2196
- checkCompletionReadiness,
2197
- init_issue,
2198
- JsonOpLog,
2199
- LaneOpLog,
2200
- init_op_log,
2201
- lanesRoot,
2202
- laneDir,
2203
- laneMetaPath,
2204
- newLaneId,
2205
- loadLaneMeta,
2206
- saveLaneMeta,
2207
- listLaneIds,
2208
- resolveLaneHeadFromJournal,
2209
- createLaneMeta,
2210
- updateLaneHead,
2211
- listLaneMetas,
2212
- init_lane
2213
- };