@flyingrobots/graft 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (665) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/README.md +1 -2
  3. package/bin/graft.js +26 -26
  4. package/dist/adapters/json-text-decoder.d.ts +3 -0
  5. package/dist/adapters/json-text-decoder.d.ts.map +1 -0
  6. package/dist/adapters/json-text-decoder.js +12 -0
  7. package/dist/adapters/json-text-decoder.js.map +1 -0
  8. package/dist/adapters/node-paths.d.ts +3 -0
  9. package/dist/adapters/node-paths.d.ts.map +1 -0
  10. package/dist/adapters/node-paths.js +29 -0
  11. package/dist/adapters/node-paths.js.map +1 -0
  12. package/dist/adapters/repo-paths.d.ts.map +1 -1
  13. package/dist/adapters/repo-paths.js +40 -5
  14. package/dist/adapters/repo-paths.js.map +1 -1
  15. package/dist/api/tool-bridge.d.ts +1 -1
  16. package/dist/api/tool-bridge.d.ts.map +1 -1
  17. package/dist/api/tool-bridge.js +1 -1
  18. package/dist/api/tool-bridge.js.map +1 -1
  19. package/dist/cli/cli-error.d.ts.map +1 -1
  20. package/dist/cli/cli-error.js +47 -10
  21. package/dist/cli/cli-error.js.map +1 -1
  22. package/dist/cli/command-parser.d.ts +12 -3
  23. package/dist/cli/command-parser.d.ts.map +1 -1
  24. package/dist/cli/command-parser.js +161 -2
  25. package/dist/cli/command-parser.js.map +1 -1
  26. package/dist/cli/daemon-status-model.d.ts +87 -0
  27. package/dist/cli/daemon-status-model.d.ts.map +1 -0
  28. package/dist/cli/daemon-status-model.js +142 -0
  29. package/dist/cli/daemon-status-model.js.map +1 -0
  30. package/dist/cli/daemon-status-render.d.ts +3 -0
  31. package/dist/cli/daemon-status-render.d.ts.map +1 -0
  32. package/dist/cli/daemon-status-render.js +100 -0
  33. package/dist/cli/daemon-status-render.js.map +1 -0
  34. package/dist/cli/daemon-status.d.ts +7 -0
  35. package/dist/cli/daemon-status.d.ts.map +1 -0
  36. package/dist/cli/daemon-status.js +79 -0
  37. package/dist/cli/daemon-status.js.map +1 -0
  38. package/dist/cli/git-graft-enhance-model.d.ts +67 -0
  39. package/dist/cli/git-graft-enhance-model.d.ts.map +1 -0
  40. package/dist/cli/git-graft-enhance-model.js +55 -0
  41. package/dist/cli/git-graft-enhance-model.js.map +1 -0
  42. package/dist/cli/git-graft-enhance-render.d.ts +3 -0
  43. package/dist/cli/git-graft-enhance-render.d.ts.map +1 -0
  44. package/dist/cli/git-graft-enhance-render.js +29 -0
  45. package/dist/cli/git-graft-enhance-render.js.map +1 -0
  46. package/dist/cli/git-graft-enhance.d.ts +14 -0
  47. package/dist/cli/git-graft-enhance.d.ts.map +1 -0
  48. package/dist/cli/git-graft-enhance.js +29 -0
  49. package/dist/cli/git-graft-enhance.js.map +1 -0
  50. package/dist/cli/index-cmd.d.ts.map +1 -1
  51. package/dist/cli/index-cmd.js +18 -21
  52. package/dist/cli/index-cmd.js.map +1 -1
  53. package/dist/cli/index-model.d.ts +5 -9
  54. package/dist/cli/index-model.d.ts.map +1 -1
  55. package/dist/cli/index-model.js +20 -18
  56. package/dist/cli/index-model.js.map +1 -1
  57. package/dist/cli/init-client-config.d.ts +12 -7
  58. package/dist/cli/init-client-config.d.ts.map +1 -1
  59. package/dist/cli/init-client-config.js +145 -47
  60. package/dist/cli/init-client-config.js.map +1 -1
  61. package/dist/cli/init-model.d.ts +9 -2
  62. package/dist/cli/init-model.d.ts.map +1 -1
  63. package/dist/cli/init-model.js +54 -6
  64. package/dist/cli/init-model.js.map +1 -1
  65. package/dist/cli/init-render.d.ts.map +1 -1
  66. package/dist/cli/init-render.js +2 -2
  67. package/dist/cli/init-render.js.map +1 -1
  68. package/dist/cli/init.d.ts.map +1 -1
  69. package/dist/cli/init.js +11 -9
  70. package/dist/cli/init.js.map +1 -1
  71. package/dist/cli/json-document.d.ts +6 -0
  72. package/dist/cli/json-document.d.ts.map +1 -1
  73. package/dist/cli/json-document.js +12 -0
  74. package/dist/cli/json-document.js.map +1 -1
  75. package/dist/cli/main.d.ts +7 -0
  76. package/dist/cli/main.d.ts.map +1 -1
  77. package/dist/cli/main.js +49 -7
  78. package/dist/cli/main.js.map +1 -1
  79. package/dist/cli/migrate-local-history.d.ts.map +1 -1
  80. package/dist/cli/migrate-local-history.js +3 -2
  81. package/dist/cli/migrate-local-history.js.map +1 -1
  82. package/dist/cli/peer-command.d.ts +1 -1
  83. package/dist/cli/peer-command.d.ts.map +1 -1
  84. package/dist/cli/peer-command.js +1 -1
  85. package/dist/cli/peer-command.js.map +1 -1
  86. package/dist/contracts/capabilities.d.ts +5 -5
  87. package/dist/contracts/capabilities.d.ts.map +1 -1
  88. package/dist/contracts/capabilities.js +89 -0
  89. package/dist/contracts/capabilities.js.map +1 -1
  90. package/dist/contracts/causal-ontology.d.ts +17 -17
  91. package/dist/contracts/json-object.d.ts +0 -1
  92. package/dist/contracts/json-object.d.ts.map +1 -1
  93. package/dist/contracts/json-object.js +0 -10
  94. package/dist/contracts/json-object.js.map +1 -1
  95. package/dist/contracts/output-schema-cli.d.ts +277 -25
  96. package/dist/contracts/output-schema-cli.d.ts.map +1 -1
  97. package/dist/contracts/output-schema-cli.js +35 -3
  98. package/dist/contracts/output-schema-cli.js.map +1 -1
  99. package/dist/contracts/output-schema-fragments.d.ts +212 -87
  100. package/dist/contracts/output-schema-fragments.d.ts.map +1 -1
  101. package/dist/contracts/output-schema-fragments.js +49 -2
  102. package/dist/contracts/output-schema-fragments.js.map +1 -1
  103. package/dist/contracts/output-schema-mcp.d.ts +372 -47
  104. package/dist/contracts/output-schema-mcp.d.ts.map +1 -1
  105. package/dist/contracts/output-schema-mcp.js +217 -1
  106. package/dist/contracts/output-schema-mcp.js.map +1 -1
  107. package/dist/contracts/output-schema-meta.d.ts +2 -2
  108. package/dist/contracts/output-schema-meta.d.ts.map +1 -1
  109. package/dist/contracts/output-schemas.d.ts +7 -7
  110. package/dist/contracts/output-schemas.d.ts.map +1 -1
  111. package/dist/contracts/output-schemas.js +294 -6
  112. package/dist/contracts/output-schemas.js.map +1 -1
  113. package/dist/git/diff.d.ts +11 -0
  114. package/dist/git/diff.d.ts.map +1 -1
  115. package/dist/git/diff.js +50 -6
  116. package/dist/git/diff.js.map +1 -1
  117. package/dist/hooks/posttooluse-read.js +1 -1
  118. package/dist/hooks/posttooluse-read.js.map +1 -1
  119. package/dist/hooks/pretooluse-read.js +1 -1
  120. package/dist/hooks/pretooluse-read.js.map +1 -1
  121. package/dist/mcp/burden.d.ts.map +1 -1
  122. package/dist/mcp/burden.js +9 -0
  123. package/dist/mcp/burden.js.map +1 -1
  124. package/dist/mcp/context.d.ts +3 -2
  125. package/dist/mcp/context.d.ts.map +1 -1
  126. package/dist/mcp/context.js +2 -37
  127. package/dist/mcp/context.js.map +1 -1
  128. package/dist/mcp/daemon-server.d.ts +2 -0
  129. package/dist/mcp/daemon-server.d.ts.map +1 -1
  130. package/dist/mcp/daemon-server.js +6 -1
  131. package/dist/mcp/daemon-server.js.map +1 -1
  132. package/dist/mcp/daemon-session-host.d.ts +1 -0
  133. package/dist/mcp/daemon-session-host.d.ts.map +1 -1
  134. package/dist/mcp/daemon-session-host.js +3 -0
  135. package/dist/mcp/daemon-session-host.js.map +1 -1
  136. package/dist/mcp/daemon-stdio-bridge.d.ts +1 -0
  137. package/dist/mcp/daemon-stdio-bridge.d.ts.map +1 -1
  138. package/dist/mcp/daemon-stdio-bridge.js +1 -0
  139. package/dist/mcp/daemon-stdio-bridge.js.map +1 -1
  140. package/dist/mcp/daemon-worker-child-pool.d.ts +2 -0
  141. package/dist/mcp/daemon-worker-child-pool.d.ts.map +1 -1
  142. package/dist/mcp/daemon-worker-child-pool.js +10 -3
  143. package/dist/mcp/daemon-worker-child-pool.js.map +1 -1
  144. package/dist/mcp/daemon-worker-pool.d.ts +1 -1
  145. package/dist/mcp/daemon-worker-pool.d.ts.map +1 -1
  146. package/dist/mcp/daemon-worker-pool.js +1 -1
  147. package/dist/mcp/daemon-worker-pool.js.map +1 -1
  148. package/dist/mcp/monitor-tick-job.d.ts +1 -0
  149. package/dist/mcp/monitor-tick-job.d.ts.map +1 -1
  150. package/dist/mcp/monitor-tick-job.js +84 -29
  151. package/dist/mcp/monitor-tick-job.js.map +1 -1
  152. package/dist/mcp/monitor-types.d.ts +1 -1
  153. package/dist/mcp/monitor-types.d.ts.map +1 -1
  154. package/dist/mcp/persisted-local-history-graph.d.ts +2 -2
  155. package/dist/mcp/persisted-local-history-graph.d.ts.map +1 -1
  156. package/dist/mcp/persisted-local-history-graph.js +3 -2
  157. package/dist/mcp/persisted-local-history-graph.js.map +1 -1
  158. package/dist/mcp/persisted-local-history.d.ts +5 -5
  159. package/dist/mcp/persisted-local-history.js +2 -2
  160. package/dist/mcp/persisted-local-history.js.map +1 -1
  161. package/dist/mcp/persistent-monitor-runtime.d.ts +1 -0
  162. package/dist/mcp/persistent-monitor-runtime.d.ts.map +1 -1
  163. package/dist/mcp/persistent-monitor-runtime.js +35 -0
  164. package/dist/mcp/persistent-monitor-runtime.js.map +1 -1
  165. package/dist/mcp/repo-tool-worker-context.d.ts.map +1 -1
  166. package/dist/mcp/repo-tool-worker-context.js +5 -2
  167. package/dist/mcp/repo-tool-worker-context.js.map +1 -1
  168. package/dist/mcp/server-context.d.ts.map +1 -1
  169. package/dist/mcp/server-context.js +13 -0
  170. package/dist/mcp/server-context.js.map +1 -1
  171. package/dist/mcp/server-tool-access.d.ts +1 -1
  172. package/dist/mcp/server-tool-access.d.ts.map +1 -1
  173. package/dist/mcp/server-tool-access.js +3 -1
  174. package/dist/mcp/server-tool-access.js.map +1 -1
  175. package/dist/mcp/server.d.ts +3 -0
  176. package/dist/mcp/server.d.ts.map +1 -1
  177. package/dist/mcp/server.js +5 -3
  178. package/dist/mcp/server.js.map +1 -1
  179. package/dist/mcp/tool-registry.d.ts.map +1 -1
  180. package/dist/mcp/tool-registry.js +18 -0
  181. package/dist/mcp/tool-registry.js.map +1 -1
  182. package/dist/mcp/tools/code-find.d.ts.map +1 -1
  183. package/dist/mcp/tools/code-find.js +20 -0
  184. package/dist/mcp/tools/code-find.js.map +1 -1
  185. package/dist/mcp/tools/code-show.d.ts.map +1 -1
  186. package/dist/mcp/tools/code-show.js +24 -0
  187. package/dist/mcp/tools/code-show.js.map +1 -1
  188. package/dist/mcp/tools/diagnostic-models.d.ts +2 -0
  189. package/dist/mcp/tools/diagnostic-models.d.ts.map +1 -1
  190. package/dist/mcp/tools/doctor.d.ts.map +1 -1
  191. package/dist/mcp/tools/doctor.js +18 -1
  192. package/dist/mcp/tools/doctor.js.map +1 -1
  193. package/dist/mcp/tools/export-surface-diff.d.ts +3 -0
  194. package/dist/mcp/tools/export-surface-diff.d.ts.map +1 -0
  195. package/dist/mcp/tools/export-surface-diff.js +24 -0
  196. package/dist/mcp/tools/export-surface-diff.js.map +1 -0
  197. package/dist/mcp/tools/file-outline.js +1 -1
  198. package/dist/mcp/tools/file-outline.js.map +1 -1
  199. package/dist/mcp/tools/graft-edit.d.ts +3 -0
  200. package/dist/mcp/tools/graft-edit.d.ts.map +1 -0
  201. package/dist/mcp/tools/graft-edit.js +192 -0
  202. package/dist/mcp/tools/graft-edit.js.map +1 -0
  203. package/dist/mcp/tools/knowledge-map.d.ts +3 -0
  204. package/dist/mcp/tools/knowledge-map.d.ts.map +1 -0
  205. package/dist/mcp/tools/knowledge-map.js +31 -0
  206. package/dist/mcp/tools/knowledge-map.js.map +1 -0
  207. package/dist/mcp/tools/monitor-nudge.d.ts +3 -0
  208. package/dist/mcp/tools/monitor-nudge.d.ts.map +1 -0
  209. package/dist/mcp/tools/monitor-nudge.js +17 -0
  210. package/dist/mcp/tools/monitor-nudge.js.map +1 -0
  211. package/dist/mcp/tools/precision-warp.d.ts +3 -3
  212. package/dist/mcp/tools/precision-warp.d.ts.map +1 -1
  213. package/dist/mcp/tools/precision-warp.js +24 -15
  214. package/dist/mcp/tools/precision-warp.js.map +1 -1
  215. package/dist/mcp/tools/refactor-difficulty.d.ts +3 -0
  216. package/dist/mcp/tools/refactor-difficulty.d.ts.map +1 -0
  217. package/dist/mcp/tools/refactor-difficulty.js +36 -0
  218. package/dist/mcp/tools/refactor-difficulty.js.map +1 -0
  219. package/dist/mcp/tools/safe-read.js +2 -2
  220. package/dist/mcp/tools/safe-read.js.map +1 -1
  221. package/dist/mcp/tools/structural-blame.d.ts +3 -0
  222. package/dist/mcp/tools/structural-blame.d.ts.map +1 -0
  223. package/dist/mcp/tools/structural-blame.js +44 -0
  224. package/dist/mcp/tools/structural-blame.js.map +1 -0
  225. package/dist/mcp/tools/structural-churn.d.ts +3 -0
  226. package/dist/mcp/tools/structural-churn.d.ts.map +1 -0
  227. package/dist/mcp/tools/structural-churn.js +28 -0
  228. package/dist/mcp/tools/structural-churn.js.map +1 -0
  229. package/dist/mcp/tools/structural-log.d.ts +3 -0
  230. package/dist/mcp/tools/structural-log.d.ts.map +1 -0
  231. package/dist/mcp/tools/structural-log.js +38 -0
  232. package/dist/mcp/tools/structural-log.js.map +1 -0
  233. package/dist/mcp/tools/structural-review.d.ts +3 -0
  234. package/dist/mcp/tools/structural-review.d.ts.map +1 -0
  235. package/dist/mcp/tools/structural-review.js +55 -0
  236. package/dist/mcp/tools/structural-review.js.map +1 -0
  237. package/dist/mcp/warp-pool.d.ts +4 -4
  238. package/dist/mcp/warp-pool.d.ts.map +1 -1
  239. package/dist/mcp/warp-pool.js.map +1 -1
  240. package/dist/mcp/workspace-router-model.d.ts +2 -2
  241. package/dist/mcp/workspace-router-model.d.ts.map +1 -1
  242. package/dist/mcp/workspace-router-runtime.d.ts +3 -3
  243. package/dist/mcp/workspace-router-runtime.d.ts.map +1 -1
  244. package/dist/mcp/workspace-router-runtime.js +4 -1
  245. package/dist/mcp/workspace-router-runtime.js.map +1 -1
  246. package/dist/mcp/workspace-router.d.ts +3 -2
  247. package/dist/mcp/workspace-router.d.ts.map +1 -1
  248. package/dist/mcp/workspace-router.js +6 -0
  249. package/dist/mcp/workspace-router.js.map +1 -1
  250. package/dist/operations/adaptive-projection.d.ts +22 -0
  251. package/dist/operations/adaptive-projection.d.ts.map +1 -0
  252. package/dist/operations/adaptive-projection.js +36 -0
  253. package/dist/operations/adaptive-projection.js.map +1 -0
  254. package/dist/operations/agent-handoff.d.ts +25 -0
  255. package/dist/operations/agent-handoff.d.ts.map +1 -0
  256. package/dist/operations/agent-handoff.js +36 -0
  257. package/dist/operations/agent-handoff.js.map +1 -0
  258. package/dist/operations/capture-range.d.ts +33 -0
  259. package/dist/operations/capture-range.d.ts.map +1 -0
  260. package/dist/operations/capture-range.js +45 -0
  261. package/dist/operations/capture-range.js.map +1 -0
  262. package/dist/operations/conversation-primer.d.ts +27 -0
  263. package/dist/operations/conversation-primer.d.ts.map +1 -0
  264. package/dist/operations/conversation-primer.js +52 -0
  265. package/dist/operations/conversation-primer.js.map +1 -0
  266. package/dist/operations/cross-session-resume.d.ts +28 -0
  267. package/dist/operations/cross-session-resume.d.ts.map +1 -0
  268. package/dist/operations/cross-session-resume.js +79 -0
  269. package/dist/operations/cross-session-resume.js.map +1 -0
  270. package/dist/operations/deterministic-replay.d.ts +39 -0
  271. package/dist/operations/deterministic-replay.d.ts.map +1 -0
  272. package/dist/operations/deterministic-replay.js +90 -0
  273. package/dist/operations/deterministic-replay.js.map +1 -0
  274. package/dist/operations/export-surface-diff.d.ts +36 -0
  275. package/dist/operations/export-surface-diff.d.ts.map +1 -0
  276. package/dist/operations/export-surface-diff.js +298 -0
  277. package/dist/operations/export-surface-diff.js.map +1 -0
  278. package/dist/operations/footprint-parallelism.d.ts +25 -0
  279. package/dist/operations/footprint-parallelism.d.ts.map +1 -0
  280. package/dist/operations/footprint-parallelism.js +79 -0
  281. package/dist/operations/footprint-parallelism.js.map +1 -0
  282. package/dist/operations/graft-diff.d.ts.map +1 -1
  283. package/dist/operations/graft-diff.js +14 -7
  284. package/dist/operations/graft-diff.js.map +1 -1
  285. package/dist/operations/horizon-of-readability.d.ts +23 -0
  286. package/dist/operations/horizon-of-readability.d.ts.map +1 -0
  287. package/dist/operations/horizon-of-readability.js +39 -0
  288. package/dist/operations/horizon-of-readability.js.map +1 -0
  289. package/dist/operations/import-reference-impact.d.ts +13 -0
  290. package/dist/operations/import-reference-impact.d.ts.map +1 -0
  291. package/dist/operations/import-reference-impact.js +101 -0
  292. package/dist/operations/import-reference-impact.js.map +1 -0
  293. package/dist/operations/knowledge-map.d.ts +30 -0
  294. package/dist/operations/knowledge-map.d.ts.map +1 -0
  295. package/dist/operations/knowledge-map.js +64 -0
  296. package/dist/operations/knowledge-map.js.map +1 -0
  297. package/dist/operations/observation-cache.d.ts +8 -2
  298. package/dist/operations/observation-cache.d.ts.map +1 -1
  299. package/dist/operations/observation-cache.js +17 -5
  300. package/dist/operations/observation-cache.js.map +1 -1
  301. package/dist/operations/projection-safety.d.ts +31 -0
  302. package/dist/operations/projection-safety.d.ts.map +1 -0
  303. package/dist/operations/projection-safety.js +77 -0
  304. package/dist/operations/projection-safety.js.map +1 -0
  305. package/dist/operations/repo-workspace.js +3 -3
  306. package/dist/operations/repo-workspace.js.map +1 -1
  307. package/dist/operations/semantic-drift.d.ts +27 -0
  308. package/dist/operations/semantic-drift.d.ts.map +1 -0
  309. package/dist/operations/semantic-drift.js +46 -0
  310. package/dist/operations/semantic-drift.js.map +1 -0
  311. package/dist/operations/session-filtration.d.ts +36 -0
  312. package/dist/operations/session-filtration.d.ts.map +1 -0
  313. package/dist/operations/session-filtration.js +48 -0
  314. package/dist/operations/session-filtration.js.map +1 -0
  315. package/dist/operations/session-replay.d.ts +17 -0
  316. package/dist/operations/session-replay.d.ts.map +1 -0
  317. package/dist/operations/session-replay.js +59 -0
  318. package/dist/operations/session-replay.js.map +1 -0
  319. package/dist/operations/sludge-detector.d.ts +45 -0
  320. package/dist/operations/sludge-detector.d.ts.map +1 -0
  321. package/dist/operations/sludge-detector.js +278 -0
  322. package/dist/operations/sludge-detector.js.map +1 -0
  323. package/dist/operations/structural-blame.d.ts +67 -0
  324. package/dist/operations/structural-blame.d.ts.map +1 -0
  325. package/dist/operations/structural-blame.js +111 -0
  326. package/dist/operations/structural-blame.js.map +1 -0
  327. package/dist/operations/structural-review.d.ts +47 -0
  328. package/dist/operations/structural-review.d.ts.map +1 -0
  329. package/dist/operations/structural-review.js +225 -0
  330. package/dist/operations/structural-review.js.map +1 -0
  331. package/dist/operations/teaching-hints.d.ts +18 -0
  332. package/dist/operations/teaching-hints.d.ts.map +1 -0
  333. package/dist/operations/teaching-hints.js +35 -0
  334. package/dist/operations/teaching-hints.js.map +1 -0
  335. package/dist/parser/diff.d.ts +2 -0
  336. package/dist/parser/diff.d.ts.map +1 -1
  337. package/dist/parser/diff.js +7 -0
  338. package/dist/parser/diff.js.map +1 -1
  339. package/dist/ports/paths.d.ts +17 -0
  340. package/dist/ports/paths.d.ts.map +1 -0
  341. package/dist/ports/{warp.js → paths.js} +2 -2
  342. package/dist/ports/paths.js.map +1 -0
  343. package/dist/version.d.ts.map +1 -1
  344. package/dist/version.js +3 -1
  345. package/dist/version.js.map +1 -1
  346. package/dist/warp/ast-emitter.d.ts +28 -0
  347. package/dist/warp/ast-emitter.d.ts.map +1 -0
  348. package/dist/warp/ast-emitter.js +90 -0
  349. package/dist/warp/ast-emitter.js.map +1 -0
  350. package/dist/warp/ast-import-resolver.d.ts +13 -0
  351. package/dist/warp/ast-import-resolver.d.ts.map +1 -0
  352. package/dist/warp/ast-import-resolver.js +259 -0
  353. package/dist/warp/ast-import-resolver.js.map +1 -0
  354. package/dist/warp/commit-meta.d.ts +8 -0
  355. package/dist/warp/commit-meta.d.ts.map +1 -0
  356. package/dist/warp/commit-meta.js +13 -0
  357. package/dist/warp/commit-meta.js.map +1 -0
  358. package/dist/warp/context.d.ts +10 -0
  359. package/dist/warp/context.d.ts.map +1 -0
  360. package/dist/warp/context.js +26 -0
  361. package/dist/warp/context.js.map +1 -0
  362. package/dist/warp/dead-symbols.d.ts +40 -0
  363. package/dist/warp/dead-symbols.d.ts.map +1 -0
  364. package/dist/warp/dead-symbols.js +127 -0
  365. package/dist/warp/dead-symbols.js.map +1 -0
  366. package/dist/warp/drift-sentinel.d.ts +30 -0
  367. package/dist/warp/drift-sentinel.d.ts.map +1 -0
  368. package/dist/warp/drift-sentinel.js +65 -0
  369. package/dist/warp/drift-sentinel.js.map +1 -0
  370. package/dist/warp/index-head.d.ts +32 -0
  371. package/dist/warp/index-head.d.ts.map +1 -0
  372. package/dist/warp/index-head.js +245 -0
  373. package/dist/warp/index-head.js.map +1 -0
  374. package/dist/warp/observers.d.ts +6 -6
  375. package/dist/warp/observers.d.ts.map +1 -1
  376. package/dist/warp/observers.js +5 -4
  377. package/dist/warp/observers.js.map +1 -1
  378. package/dist/warp/open.d.ts +5 -4
  379. package/dist/warp/open.d.ts.map +1 -1
  380. package/dist/warp/open.js +24 -49
  381. package/dist/warp/open.js.map +1 -1
  382. package/dist/warp/outline-diff-trailer.d.ts +26 -0
  383. package/dist/warp/outline-diff-trailer.d.ts.map +1 -0
  384. package/dist/warp/outline-diff-trailer.js +68 -0
  385. package/dist/warp/outline-diff-trailer.js.map +1 -0
  386. package/dist/warp/refactor-difficulty.d.ts +38 -0
  387. package/dist/warp/refactor-difficulty.d.ts.map +1 -0
  388. package/dist/warp/refactor-difficulty.js +169 -0
  389. package/dist/warp/refactor-difficulty.js.map +1 -0
  390. package/dist/warp/references.d.ts +22 -0
  391. package/dist/warp/references.d.ts.map +1 -0
  392. package/dist/warp/references.js +57 -0
  393. package/dist/warp/references.js.map +1 -0
  394. package/dist/warp/stale-docs.d.ts +56 -0
  395. package/dist/warp/stale-docs.d.ts.map +1 -0
  396. package/dist/warp/stale-docs.js +149 -0
  397. package/dist/warp/stale-docs.js.map +1 -0
  398. package/dist/warp/structural-drift-detection.d.ts +49 -0
  399. package/dist/warp/structural-drift-detection.d.ts.map +1 -0
  400. package/dist/warp/structural-drift-detection.js +51 -0
  401. package/dist/warp/structural-drift-detection.js.map +1 -0
  402. package/dist/warp/structural-queries.d.ts +49 -0
  403. package/dist/warp/structural-queries.d.ts.map +1 -0
  404. package/dist/warp/structural-queries.js +175 -0
  405. package/dist/warp/structural-queries.js.map +1 -0
  406. package/dist/warp/symbol-timeline.d.ts +34 -0
  407. package/dist/warp/symbol-timeline.d.ts.map +1 -0
  408. package/dist/warp/symbol-timeline.js +127 -0
  409. package/dist/warp/symbol-timeline.js.map +1 -0
  410. package/dist/warp/traverse-hydrate.d.ts +23 -0
  411. package/dist/warp/traverse-hydrate.d.ts.map +1 -0
  412. package/dist/warp/traverse-hydrate.js +39 -0
  413. package/dist/warp/traverse-hydrate.js.map +1 -0
  414. package/dist/warp/warp-reference-count.d.ts +19 -0
  415. package/dist/warp/warp-reference-count.d.ts.map +1 -0
  416. package/dist/warp/warp-reference-count.js +32 -0
  417. package/dist/warp/warp-reference-count.js.map +1 -0
  418. package/dist/warp/warp-structural-blame.d.ts +20 -0
  419. package/dist/warp/warp-structural-blame.d.ts.map +1 -0
  420. package/dist/warp/warp-structural-blame.js +43 -0
  421. package/dist/warp/warp-structural-blame.js.map +1 -0
  422. package/dist/warp/warp-structural-churn.d.ts +30 -0
  423. package/dist/warp/warp-structural-churn.d.ts.map +1 -0
  424. package/dist/warp/warp-structural-churn.js +213 -0
  425. package/dist/warp/warp-structural-churn.js.map +1 -0
  426. package/dist/warp/warp-structural-log.d.ts +35 -0
  427. package/dist/warp/warp-structural-log.d.ts.map +1 -0
  428. package/dist/warp/warp-structural-log.js +104 -0
  429. package/dist/warp/warp-structural-log.js.map +1 -0
  430. package/docs/CLI.md +68 -4
  431. package/docs/MCP.md +23 -0
  432. package/docs/SETUP.md +112 -27
  433. package/package.json +13 -6
  434. package/dist/ports/warp.d.ts +0 -45
  435. package/dist/ports/warp.d.ts.map +0 -1
  436. package/dist/ports/warp.js.map +0 -1
  437. package/dist/warp/identity-resolver.d.ts +0 -14
  438. package/dist/warp/identity-resolver.d.ts.map +0 -1
  439. package/dist/warp/identity-resolver.js +0 -31
  440. package/dist/warp/identity-resolver.js.map +0 -1
  441. package/dist/warp/indexer-git.d.ts +0 -22
  442. package/dist/warp/indexer-git.d.ts.map +0 -1
  443. package/dist/warp/indexer-git.js +0 -148
  444. package/dist/warp/indexer-git.js.map +0 -1
  445. package/dist/warp/indexer-graph.d.ts +0 -17
  446. package/dist/warp/indexer-graph.d.ts.map +0 -1
  447. package/dist/warp/indexer-graph.js +0 -179
  448. package/dist/warp/indexer-graph.js.map +0 -1
  449. package/dist/warp/indexer-model.d.ts +0 -51
  450. package/dist/warp/indexer-model.d.ts.map +0 -1
  451. package/dist/warp/indexer-model.js +0 -21
  452. package/dist/warp/indexer-model.js.map +0 -1
  453. package/dist/warp/indexer.d.ts +0 -9
  454. package/dist/warp/indexer.d.ts.map +0 -1
  455. package/dist/warp/indexer.js +0 -112
  456. package/dist/warp/indexer.js.map +0 -1
  457. package/dist/warp/symbol-identity.d.ts +0 -11
  458. package/dist/warp/symbol-identity.d.ts.map +0 -1
  459. package/dist/warp/symbol-identity.js +0 -67
  460. package/dist/warp/symbol-identity.js.map +0 -1
  461. package/src/adapters/canonical-json.ts +0 -56
  462. package/src/adapters/node-fs.ts +0 -43
  463. package/src/adapters/node-git.ts +0 -47
  464. package/src/adapters/node-process-runner.ts +0 -27
  465. package/src/adapters/repo-paths.ts +0 -22
  466. package/src/adapters/rotating-ndjson-log.ts +0 -66
  467. package/src/api/index.ts +0 -107
  468. package/src/api/repo-local-graft.ts +0 -21
  469. package/src/api/repo-workspace.ts +0 -34
  470. package/src/api/tool-bridge.ts +0 -21
  471. package/src/cli/activity-render.ts +0 -112
  472. package/src/cli/cli-error.ts +0 -153
  473. package/src/cli/command-parser.ts +0 -302
  474. package/src/cli/entrypoint.ts +0 -18
  475. package/src/cli/index-cmd.ts +0 -94
  476. package/src/cli/index-model.ts +0 -76
  477. package/src/cli/init-bootstrap.ts +0 -47
  478. package/src/cli/init-client-config.ts +0 -299
  479. package/src/cli/init-model.ts +0 -229
  480. package/src/cli/init-render.ts +0 -54
  481. package/src/cli/init-target-hooks.ts +0 -93
  482. package/src/cli/init.ts +0 -122
  483. package/src/cli/json-document.ts +0 -144
  484. package/src/cli/local-history-dag-model.ts +0 -437
  485. package/src/cli/local-history-dag-render.ts +0 -133
  486. package/src/cli/local-history-dag.ts +0 -103
  487. package/src/cli/main.ts +0 -150
  488. package/src/cli/migrate-local-history.ts +0 -118
  489. package/src/cli/peer-command.ts +0 -59
  490. package/src/contracts/capabilities.ts +0 -450
  491. package/src/contracts/causal-ontology.ts +0 -627
  492. package/src/contracts/causal-surface-next-action.ts +0 -18
  493. package/src/contracts/json-object.ts +0 -28
  494. package/src/contracts/mcp-runtime.ts +0 -16
  495. package/src/contracts/output-schema-cli.ts +0 -70
  496. package/src/contracts/output-schema-fragments.ts +0 -831
  497. package/src/contracts/output-schema-mcp.ts +0 -282
  498. package/src/contracts/output-schema-meta.ts +0 -119
  499. package/src/contracts/output-schemas.ts +0 -1230
  500. package/src/git/diff.ts +0 -100
  501. package/src/git/target-git-hook-bootstrap.ts +0 -56
  502. package/src/guards/stream-boundary.ts +0 -110
  503. package/src/hooks/posttooluse-read.ts +0 -54
  504. package/src/hooks/pretooluse-read.ts +0 -52
  505. package/src/hooks/read-governor.ts +0 -95
  506. package/src/hooks/read-messages.ts +0 -53
  507. package/src/hooks/shared.ts +0 -168
  508. package/src/index.ts +0 -1
  509. package/src/mcp/burden.ts +0 -123
  510. package/src/mcp/cache.ts +0 -7
  511. package/src/mcp/cached-file.ts +0 -1
  512. package/src/mcp/context.ts +0 -187
  513. package/src/mcp/control-plane/authz-storage.ts +0 -129
  514. package/src/mcp/control-plane/session-registry.ts +0 -115
  515. package/src/mcp/control-plane/status-projection.ts +0 -76
  516. package/src/mcp/control-plane/types.ts +0 -144
  517. package/src/mcp/daemon-bootstrap.ts +0 -100
  518. package/src/mcp/daemon-control-plane.ts +0 -310
  519. package/src/mcp/daemon-job-scheduler.ts +0 -279
  520. package/src/mcp/daemon-repos.ts +0 -99
  521. package/src/mcp/daemon-server.ts +0 -165
  522. package/src/mcp/daemon-session-host.ts +0 -230
  523. package/src/mcp/daemon-stdio-bridge.ts +0 -260
  524. package/src/mcp/daemon-worker-child-pool.ts +0 -213
  525. package/src/mcp/daemon-worker-inline-pool.ts +0 -46
  526. package/src/mcp/daemon-worker-pool.ts +0 -7
  527. package/src/mcp/daemon-worker-process.ts +0 -52
  528. package/src/mcp/daemon-worker-types.ts +0 -66
  529. package/src/mcp/metrics.ts +0 -176
  530. package/src/mcp/monitor-health.ts +0 -83
  531. package/src/mcp/monitor-persistence.ts +0 -54
  532. package/src/mcp/monitor-tick-job.ts +0 -102
  533. package/src/mcp/monitor-types.ts +0 -103
  534. package/src/mcp/persisted-local-history-graph.ts +0 -591
  535. package/src/mcp/persisted-local-history-policy.ts +0 -501
  536. package/src/mcp/persisted-local-history-views.ts +0 -250
  537. package/src/mcp/persisted-local-history.ts +0 -1621
  538. package/src/mcp/persistent-monitor-runtime.ts +0 -445
  539. package/src/mcp/policy.ts +0 -75
  540. package/src/mcp/receipt.ts +0 -201
  541. package/src/mcp/repo-concurrency.ts +0 -392
  542. package/src/mcp/repo-overview/filter.ts +0 -44
  543. package/src/mcp/repo-overview/types.ts +0 -63
  544. package/src/mcp/repo-overview/view-projection.ts +0 -90
  545. package/src/mcp/repo-state-git.ts +0 -247
  546. package/src/mcp/repo-state-observation.ts +0 -203
  547. package/src/mcp/repo-state-transition.ts +0 -151
  548. package/src/mcp/repo-state-types.ts +0 -107
  549. package/src/mcp/repo-state.ts +0 -146
  550. package/src/mcp/repo-tool-job.ts +0 -102
  551. package/src/mcp/repo-tool-worker-context.ts +0 -212
  552. package/src/mcp/repo-workspace.ts +0 -21
  553. package/src/mcp/run-capture-config.ts +0 -33
  554. package/src/mcp/runtime-causal-context.ts +0 -72
  555. package/src/mcp/runtime-observability.ts +0 -217
  556. package/src/mcp/runtime-staged-target.ts +0 -161
  557. package/src/mcp/runtime-workspace-overlay.ts +0 -255
  558. package/src/mcp/secret-scrub.ts +0 -89
  559. package/src/mcp/semantic-transition-guidance.ts +0 -60
  560. package/src/mcp/semantic-transition-summary.ts +0 -130
  561. package/src/mcp/server-context.ts +0 -223
  562. package/src/mcp/server-invocation.ts +0 -388
  563. package/src/mcp/server-tool-access.ts +0 -145
  564. package/src/mcp/server.ts +0 -265
  565. package/src/mcp/stdio-server.ts +0 -26
  566. package/src/mcp/stdio.ts +0 -3
  567. package/src/mcp/tool-registry.ts +0 -80
  568. package/src/mcp/tools/activity-view.ts +0 -325
  569. package/src/mcp/tools/budget.ts +0 -23
  570. package/src/mcp/tools/causal-attach.ts +0 -67
  571. package/src/mcp/tools/causal-status.ts +0 -58
  572. package/src/mcp/tools/changed-since.ts +0 -71
  573. package/src/mcp/tools/code-find.ts +0 -169
  574. package/src/mcp/tools/code-refs.ts +0 -470
  575. package/src/mcp/tools/code-show.ts +0 -262
  576. package/src/mcp/tools/daemon-monitors.ts +0 -14
  577. package/src/mcp/tools/daemon-repos.ts +0 -22
  578. package/src/mcp/tools/daemon-sessions.ts +0 -14
  579. package/src/mcp/tools/daemon-status.ts +0 -12
  580. package/src/mcp/tools/diagnostic-models.ts +0 -95
  581. package/src/mcp/tools/doctor.ts +0 -66
  582. package/src/mcp/tools/explain.ts +0 -84
  583. package/src/mcp/tools/file-outline.ts +0 -67
  584. package/src/mcp/tools/git-files.ts +0 -73
  585. package/src/mcp/tools/graft-diff.ts +0 -35
  586. package/src/mcp/tools/map-collector.ts +0 -338
  587. package/src/mcp/tools/map.ts +0 -185
  588. package/src/mcp/tools/monitor-pause.ts +0 -18
  589. package/src/mcp/tools/monitor-resume.ts +0 -18
  590. package/src/mcp/tools/monitor-start.ts +0 -20
  591. package/src/mcp/tools/monitor-stop.ts +0 -18
  592. package/src/mcp/tools/precision-live.ts +0 -158
  593. package/src/mcp/tools/precision-match.ts +0 -54
  594. package/src/mcp/tools/precision-paths.ts +0 -59
  595. package/src/mcp/tools/precision-query.ts +0 -127
  596. package/src/mcp/tools/precision-show.ts +0 -86
  597. package/src/mcp/tools/precision-visibility.ts +0 -44
  598. package/src/mcp/tools/precision-warp.ts +0 -90
  599. package/src/mcp/tools/precision.ts +0 -21
  600. package/src/mcp/tools/read-range.ts +0 -28
  601. package/src/mcp/tools/run-capture.ts +0 -149
  602. package/src/mcp/tools/safe-read.ts +0 -148
  603. package/src/mcp/tools/since.ts +0 -53
  604. package/src/mcp/tools/state.ts +0 -39
  605. package/src/mcp/tools/stats.ts +0 -24
  606. package/src/mcp/tools/workspace-authorizations.ts +0 -14
  607. package/src/mcp/tools/workspace-authorize.ts +0 -20
  608. package/src/mcp/tools/workspace-bind.ts +0 -25
  609. package/src/mcp/tools/workspace-rebind.ts +0 -25
  610. package/src/mcp/tools/workspace-revoke.ts +0 -18
  611. package/src/mcp/tools/workspace-status.ts +0 -12
  612. package/src/mcp/warp-pool.ts +0 -36
  613. package/src/mcp/workspace-read-observation-model.ts +0 -48
  614. package/src/mcp/workspace-read-observation.ts +0 -103
  615. package/src/mcp/workspace-router-capability.ts +0 -32
  616. package/src/mcp/workspace-router-history.ts +0 -233
  617. package/src/mcp/workspace-router-model.ts +0 -131
  618. package/src/mcp/workspace-router-resolution.ts +0 -71
  619. package/src/mcp/workspace-router-runtime.ts +0 -243
  620. package/src/mcp/workspace-router.ts +0 -681
  621. package/src/metrics/logger.ts +0 -40
  622. package/src/metrics/types.ts +0 -40
  623. package/src/operations/cached-file.ts +0 -40
  624. package/src/operations/diff-identity.ts +0 -127
  625. package/src/operations/file-outline.ts +0 -48
  626. package/src/operations/graft-diff.ts +0 -162
  627. package/src/operations/observation-cache.ts +0 -149
  628. package/src/operations/read-range.ts +0 -64
  629. package/src/operations/repo-workspace.ts +0 -339
  630. package/src/operations/result-dto.ts +0 -23
  631. package/src/operations/safe-read.ts +0 -118
  632. package/src/operations/state.ts +0 -66
  633. package/src/operations/structured-buffer-compare.ts +0 -429
  634. package/src/operations/structured-buffer-model.ts +0 -456
  635. package/src/operations/structured-buffer-query.ts +0 -794
  636. package/src/operations/structured-buffer.ts +0 -181
  637. package/src/parser/diff.ts +0 -313
  638. package/src/parser/lang.ts +0 -71
  639. package/src/parser/markdown.ts +0 -197
  640. package/src/parser/outline.ts +0 -316
  641. package/src/parser/runtime.ts +0 -71
  642. package/src/parser/types.ts +0 -75
  643. package/src/policy/evaluate.ts +0 -178
  644. package/src/policy/graftignore.ts +0 -6
  645. package/src/policy/types.ts +0 -87
  646. package/src/ports/codec.ts +0 -13
  647. package/src/ports/filesystem.ts +0 -18
  648. package/src/ports/git.ts +0 -16
  649. package/src/ports/guards.ts +0 -68
  650. package/src/ports/process-runner.ts +0 -22
  651. package/src/ports/warp.ts +0 -55
  652. package/src/release/security-gate.ts +0 -102
  653. package/src/session/tracker.ts +0 -145
  654. package/src/session/types.ts +0 -23
  655. package/src/version.ts +0 -3
  656. package/src/warp/identity-resolver.ts +0 -35
  657. package/src/warp/indexer-git.ts +0 -182
  658. package/src/warp/indexer-graph.ts +0 -276
  659. package/src/warp/indexer-model.ts +0 -69
  660. package/src/warp/indexer.ts +0 -186
  661. package/src/warp/observers.ts +0 -100
  662. package/src/warp/open.ts +0 -93
  663. package/src/warp/plumbing.d.ts +0 -15
  664. package/src/warp/symbol-identity.ts +0 -100
  665. package/src/warp/writer-id.ts +0 -30
@@ -1,1621 +0,0 @@
1
- import * as crypto from "node:crypto";
2
- import * as path from "node:path";
3
- import { z } from "zod";
4
- import {
5
- actorSchema,
6
- attributionSummarySchema,
7
- attributionConfidenceSchema,
8
- causalFootprintSchema,
9
- causalRegionSchema,
10
- readEventSchema,
11
- stageEventSchema,
12
- transitionEventSchema,
13
- evidenceSchema,
14
- localHistoryContinuityOperationSchema,
15
- type AttributionSummary,
16
- type AttributionConfidence,
17
- type Actor,
18
- type CausalEvent,
19
- type CausalFootprint,
20
- type Evidence,
21
- type LocalHistoryContinuityOperation,
22
- type SourceLayer,
23
- } from "../contracts/causal-ontology.js";
24
- import type { JsonCodec } from "../ports/codec.js";
25
- import type { FileSystem } from "../ports/filesystem.js";
26
- import type { RepoObservation } from "./repo-state.js";
27
- import {
28
- type PersistedLocalHistoryGraphContext,
29
- writeCausalEventToGraph,
30
- writeContinuityRecordToGraph,
31
- } from "./persisted-local-history-graph.js";
32
- import {
33
- deriveRepoConcurrencySummary,
34
- type RepoConcurrencySummary,
35
- } from "./repo-concurrency.js";
36
- import {
37
- buildPersistedLocalActivityWindow,
38
- emptyPersistedLocalActivityWindow,
39
- emptyPersistedLocalHistorySummary,
40
- findRecord,
41
- summarizeContinuityState,
42
- toRepoConcurrencyWorktreeHistory,
43
- } from "./persisted-local-history-views.js";
44
- import {
45
- buildAttachDeclarationEvidence,
46
- buildGitTransitionEvidence,
47
- buildUnknownAttributionForActorId,
48
- classifyContinuityOperation,
49
- createContinuityRecord,
50
- createReadEvent,
51
- createStageEvent,
52
- createTransitionEvent,
53
- deriveContinuityAttribution,
54
- } from "./persisted-local-history-policy.js";
55
- import type { GitTransitionHookEvent } from "./runtime-workspace-overlay.js";
56
- import type { RuntimeCausalContext } from "./runtime-causal-context.js";
57
- import type { RuntimeStagedTargetFullFile } from "./runtime-staged-target.js";
58
- import type { WorkspaceStatus } from "./workspace-router.js";
59
-
60
- const PERSISTED_LOCAL_HISTORY_PRESERVES = Object.freeze([
61
- "continuity_operations",
62
- "read_events",
63
- "stage_events",
64
- "transition_events",
65
- "runtime_context_ids",
66
- "workspace_overlay_snapshots",
67
- ] as const);
68
-
69
- const PERSISTED_LOCAL_HISTORY_EXCLUDES = Object.freeze([
70
- "raw_chat_transcripts",
71
- "queue_bookkeeping",
72
- "canonical_provenance",
73
- "canonical_structural_truth",
74
- ] as const);
75
-
76
- const MAX_CONTINUITY_RECORDS = 128;
77
- const MAX_READ_EVENTS = 256;
78
- const MAX_STAGE_EVENTS = 128;
79
- const MAX_TRANSITION_EVENTS = 128;
80
-
81
- const continuityRecordSchema = z.object({
82
- recordId: z.string().min(1),
83
- continuityKey: z.string().min(1),
84
- operation: localHistoryContinuityOperationSchema,
85
- repoId: z.string().min(1),
86
- worktreeId: z.string().min(1),
87
- transportSessionId: z.string().min(1),
88
- workspaceSliceId: z.string().min(1),
89
- causalSessionId: z.string().min(1),
90
- strandId: z.string().min(1),
91
- checkoutEpochId: z.string().min(1),
92
- workspaceOverlayId: z.string().min(1).nullable(),
93
- occurredAt: z.string().min(1),
94
- continuedFromRecordId: z.string().min(1).nullable(),
95
- continuedFromCausalSessionId: z.string().min(1).nullable(),
96
- continuedFromStrandId: z.string().min(1).nullable(),
97
- continuityConfidence: attributionConfidenceSchema,
98
- continuityEvidence: z.array(evidenceSchema),
99
- attribution: attributionSummarySchema,
100
- }).strict();
101
-
102
- export type ContinuityRecord = z.infer<typeof continuityRecordSchema>;
103
-
104
- const continuityStateSchema = z.object({
105
- continuityKey: z.string().min(1),
106
- repoId: z.string().min(1),
107
- worktreeId: z.string().min(1),
108
- activeRecordId: z.string().min(1).nullable(),
109
- records: z.array(continuityRecordSchema),
110
- readEvents: z.array(readEventSchema),
111
- stageEvents: z.array(stageEventSchema),
112
- transitionEvents: z.array(transitionEventSchema),
113
- }).strict();
114
-
115
- export type ContinuityState = z.infer<typeof continuityStateSchema>;
116
-
117
- export interface PersistedLocalHistoryContext {
118
- readonly repoId: string;
119
- readonly worktreeId: string;
120
- readonly transportSessionId: string;
121
- readonly workspaceSliceId: string;
122
- readonly causalSessionId: string;
123
- readonly strandId: string;
124
- readonly checkoutEpochId: string;
125
- readonly workspaceOverlayId: string | null;
126
- readonly observedAt: string;
127
- readonly warpWriterId: string;
128
- readonly transitionKind: RepoObservation["lastTransition"] extends infer T
129
- ? T extends { kind: infer K } | null
130
- ? K | null
131
- : null
132
- : null;
133
- readonly transitionReflogSubject: string | null;
134
- readonly hookTransitionName: GitTransitionHookEvent["hookName"] | null;
135
- readonly hookTransitionArgs: readonly string[] | null;
136
- readonly hookTransitionObservedAt: string | null;
137
- }
138
-
139
- export interface PersistedLocalHistoryAttachDeclaration {
140
- readonly actorKind: "human" | "agent";
141
- readonly actorId?: string | undefined;
142
- readonly fromActorId?: string | undefined;
143
- readonly note?: string | undefined;
144
- }
145
-
146
- export interface PersistedLocalHistorySharedAttachSource {
147
- readonly sourceSessionId: string;
148
- readonly causalSessionId: string;
149
- readonly strandId: string;
150
- }
151
-
152
- export interface PersistedLocalHistorySummaryNone {
153
- readonly availability: "none";
154
- readonly persistence: "persisted_local_history";
155
- readonly historyPath: null;
156
- readonly totalContinuityRecords: 0;
157
- readonly active: false;
158
- readonly lastOperation: null;
159
- readonly lastObservedAt: null;
160
- readonly continuityKey: null;
161
- readonly causalSessionId: null;
162
- readonly strandId: null;
163
- readonly checkoutEpochId: null;
164
- readonly continuedFromCausalSessionId: null;
165
- readonly continuityConfidence: AttributionConfidence;
166
- readonly continuityEvidence: readonly Evidence[];
167
- readonly attribution: AttributionSummary;
168
- readonly latestReadEvent: null;
169
- readonly latestStageEvent: null;
170
- readonly latestTransitionEvent: null;
171
- readonly preserves: readonly string[];
172
- readonly excludes: readonly string[];
173
- readonly nextAction: "bind_workspace_to_begin_local_history";
174
- }
175
-
176
- export interface PersistedLocalHistorySummaryPresent {
177
- readonly availability: "present";
178
- readonly persistence: "persisted_local_history";
179
- readonly historyPath: string | null;
180
- readonly totalContinuityRecords: number;
181
- readonly active: boolean;
182
- readonly lastOperation: LocalHistoryContinuityOperation;
183
- readonly lastObservedAt: string;
184
- readonly continuityKey: string;
185
- readonly causalSessionId: string;
186
- readonly strandId: string;
187
- readonly checkoutEpochId: string;
188
- readonly continuedFromCausalSessionId: string | null;
189
- readonly continuityConfidence: AttributionConfidence;
190
- readonly continuityEvidence: readonly Evidence[];
191
- readonly attribution: AttributionSummary;
192
- readonly latestReadEvent: Extract<CausalEvent, { eventKind: "read" }> | null;
193
- readonly latestStageEvent: Extract<CausalEvent, { eventKind: "stage" }> | null;
194
- readonly latestTransitionEvent: Extract<CausalEvent, { eventKind: "transition" }> | null;
195
- readonly preserves: readonly string[];
196
- readonly excludes: readonly string[];
197
- readonly nextAction:
198
- | "continue_active_causal_workspace"
199
- | "review_transition_boundary_before_continuing"
200
- | "inspect_or_resume_local_history";
201
- }
202
-
203
- export type PersistedLocalHistorySummary =
204
- | PersistedLocalHistorySummaryNone
205
- | PersistedLocalHistorySummaryPresent;
206
-
207
- export interface PersistedLocalActivityContinuityItem {
208
- readonly itemKind: "continuity";
209
- readonly recordId: string;
210
- readonly operation: LocalHistoryContinuityOperation;
211
- readonly occurredAt: string;
212
- readonly causalSessionId: string;
213
- readonly strandId: string;
214
- readonly attribution: AttributionSummary;
215
- readonly continuedFromCausalSessionId: string | null;
216
- readonly continuedFromStrandId: string | null;
217
- }
218
-
219
- export type PersistedLocalActivityItem =
220
- | PersistedLocalActivityContinuityItem
221
- | Extract<CausalEvent, { eventKind: "read" | "stage" | "transition" }>;
222
-
223
- export interface PersistedLocalActivityWindow {
224
- readonly historyPath: string | null;
225
- readonly limit: number;
226
- readonly totalMatchingItems: number;
227
- readonly truncated: boolean;
228
- readonly items: readonly PersistedLocalActivityItem[];
229
- }
230
-
231
- export type { RepoConcurrencySummary } from "./repo-concurrency.js";
232
-
233
- export class PersistedLocalHistoryAttachUnavailableError extends Error {
234
- readonly code = "NO_ATTACHABLE_HISTORY";
235
-
236
- constructor(message = "No attachable persisted local-history lineage is available for the current footing.") {
237
- super(message);
238
- this.name = "PersistedLocalHistoryAttachUnavailableError";
239
- }
240
- }
241
-
242
- function stableId(prefix: string, input: string): string {
243
- return `${prefix}:${crypto.createHash("sha256").update(input).digest("hex").slice(0, 16)}`;
244
- }
245
-
246
- export function buildContinuityKey(repoId: string, worktreeId: string): string {
247
- return stableId("continuity", `${repoId}:${worktreeId}`);
248
- }
249
-
250
- function buildEvidenceId(
251
- operation: LocalHistoryContinuityOperation,
252
- kind: Evidence["evidenceKind"],
253
- context: PersistedLocalHistoryContext,
254
- index: number,
255
- ): string {
256
- return stableId(
257
- "evidence",
258
- JSON.stringify({
259
- operation,
260
- kind,
261
- index,
262
- occurredAt: context.observedAt,
263
- transportSessionId: context.transportSessionId,
264
- causalSessionId: context.causalSessionId,
265
- strandId: context.strandId,
266
- }),
267
- );
268
- }
269
-
270
- function createEmptyState(continuityKey: string, repoId: string, worktreeId: string): ContinuityState {
271
- return {
272
- continuityKey,
273
- repoId,
274
- worktreeId,
275
- activeRecordId: null,
276
- records: [],
277
- readEvents: [],
278
- stageEvents: [],
279
- transitionEvents: [],
280
- };
281
- }
282
-
283
- function appendRecord(state: ContinuityState, record: ContinuityRecord, activeAfter: boolean): void {
284
- if (state.records.at(-1)?.recordId === record.recordId) {
285
- state.activeRecordId = activeAfter ? record.recordId : null;
286
- return;
287
- }
288
- state.records = [...state.records, record].slice(-MAX_CONTINUITY_RECORDS);
289
- state.activeRecordId = activeAfter ? record.recordId : null;
290
- }
291
-
292
- function keepRecent<T>(items: readonly T[], limit: number): T[] {
293
- return items.slice(-limit);
294
- }
295
-
296
- function compareByOccurredAtThenId(
297
- left: { readonly occurredAt: string; readonly id: string },
298
- right: { readonly occurredAt: string; readonly id: string },
299
- ): number {
300
- const byTime = left.occurredAt.localeCompare(right.occurredAt);
301
- if (byTime !== 0) {
302
- return byTime;
303
- }
304
- return left.id.localeCompare(right.id);
305
- }
306
-
307
- function asString(value: unknown): string | undefined {
308
- return typeof value === "string" && value.length > 0 ? value : undefined;
309
- }
310
-
311
- function asNullableString(value: unknown): string | null | undefined {
312
- if (value === null) {
313
- return null;
314
- }
315
- return asString(value);
316
- }
317
-
318
- function asStringArray(value: unknown): string[] | undefined {
319
- if (!Array.isArray(value)) {
320
- return undefined;
321
- }
322
- const strings: string[] = [];
323
- for (const entry of value) {
324
- if (typeof entry !== "string" || entry.length === 0) {
325
- return undefined;
326
- }
327
- strings.push(entry);
328
- }
329
- return strings;
330
- }
331
-
332
- function asUnknownRecord(value: unknown): Record<string, unknown> | undefined {
333
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
334
- return undefined;
335
- }
336
- return value as Record<string, unknown>;
337
- }
338
-
339
- interface ObservedLocalHistoryNode {
340
- readonly id: string;
341
- readonly props: Record<string, unknown>;
342
- }
343
-
344
- interface ObservedLocalHistoryEdge {
345
- readonly from: string;
346
- readonly to: string;
347
- readonly label: string;
348
- }
349
-
350
- interface ObservedLocalHistoryGraphSnapshot {
351
- readonly nodesById: ReadonlyMap<string, ObservedLocalHistoryNode>;
352
- readonly outgoingEdges: ReadonlyMap<string, readonly ObservedLocalHistoryEdge[]>;
353
- }
354
-
355
- const LOCAL_HISTORY_GRAPH_MATCH = ["lh:*"] as const;
356
- const LOCAL_HISTORY_GRAPH_EXPOSE = [
357
- "actorId",
358
- "actorKind",
359
- "authority",
360
- "authorityScope",
361
- "attributionBasis",
362
- "attributionConfidence",
363
- "capturedAt",
364
- "causalSessionId",
365
- "checkoutEpochId",
366
- "continuityKey",
367
- "continuityOperation",
368
- "continuedFromCausalSessionId",
369
- "continuedFromEventId",
370
- "continuedFromStrandId",
371
- "details",
372
- "displayName",
373
- "entityKind",
374
- "eventId",
375
- "eventKind",
376
- "evidenceId",
377
- "evidenceKind",
378
- "fromRef",
379
- "occurredAt",
380
- "path",
381
- "paths",
382
- "phase",
383
- "projection",
384
- "reason",
385
- "repoId",
386
- "selectionKind",
387
- "semanticKind",
388
- "source",
389
- "sourceLayer",
390
- "startLine",
391
- "endLine",
392
- "strandId",
393
- "strength",
394
- "summary",
395
- "surface",
396
- "symbols",
397
- "targetId",
398
- "toRef",
399
- "transitionKind",
400
- "transportSessionId",
401
- "workspaceOverlayId",
402
- "workspaceSliceId",
403
- "worktreeId",
404
- "createdCheckoutEpochId",
405
- ] as const;
406
-
407
- function sortEvidence(evidence: readonly Evidence[]): Evidence[] {
408
- return [...evidence].sort((left, right) => {
409
- const byCapturedAt = left.capturedAt.localeCompare(right.capturedAt);
410
- if (byCapturedAt !== 0) {
411
- return byCapturedAt;
412
- }
413
- return left.evidenceId.localeCompare(right.evidenceId);
414
- });
415
- }
416
-
417
- function sortEvents<T extends { readonly occurredAt: string; readonly eventId: string }>(events: readonly T[]): T[] {
418
- return [...events].sort((left, right) => compareByOccurredAtThenId(
419
- { occurredAt: left.occurredAt, id: left.eventId },
420
- { occurredAt: right.occurredAt, id: right.eventId },
421
- ));
422
- }
423
-
424
- function sortContinuityRecords(records: readonly ContinuityRecord[]): ContinuityRecord[] {
425
- return [...records].sort((left, right) => {
426
- const byTime = left.occurredAt.localeCompare(right.occurredAt);
427
- if (byTime !== 0) {
428
- return byTime;
429
- }
430
- if (left.continuedFromRecordId === right.recordId) {
431
- return 1;
432
- }
433
- if (right.continuedFromRecordId === left.recordId) {
434
- return -1;
435
- }
436
- if (left.operation !== right.operation) {
437
- if (left.operation === "park") {
438
- return -1;
439
- }
440
- if (right.operation === "park") {
441
- return 1;
442
- }
443
- }
444
- return left.recordId.localeCompare(right.recordId);
445
- });
446
- }
447
-
448
- function outgoingTargets(
449
- snapshot: ObservedLocalHistoryGraphSnapshot,
450
- nodeId: string,
451
- label: string,
452
- ): string[] {
453
- return (snapshot.outgoingEdges.get(nodeId) ?? [])
454
- .filter((edge) => edge.label === label)
455
- .map((edge) => edge.to);
456
- }
457
-
458
- async function loadObservedLocalHistoryGraph(
459
- graph: PersistedLocalHistoryGraphContext | null | undefined,
460
- ): Promise<ObservedLocalHistoryGraphSnapshot | null> {
461
- if (graph === null || graph === undefined) {
462
- return null;
463
- }
464
-
465
- const observer = await graph.warp.observer({
466
- match: [...LOCAL_HISTORY_GRAPH_MATCH],
467
- expose: [...LOCAL_HISTORY_GRAPH_EXPOSE],
468
- });
469
- const nodeIds = await observer.getNodes();
470
- if (nodeIds.length === 0) {
471
- return null;
472
- }
473
-
474
- const nodesById = new Map<string, ObservedLocalHistoryNode>();
475
- for (const nodeId of nodeIds) {
476
- const props = await observer.getNodeProps(nodeId);
477
- const record = asUnknownRecord(props);
478
- if (record !== undefined) {
479
- nodesById.set(nodeId, { id: nodeId, props: record });
480
- }
481
- }
482
-
483
- if (nodesById.size === 0) {
484
- return null;
485
- }
486
-
487
- const outgoing = new Map<string, ObservedLocalHistoryEdge[]>();
488
- for (const edge of await observer.getEdges()) {
489
- if (!nodesById.has(edge.from) || !nodesById.has(edge.to)) {
490
- continue;
491
- }
492
- const bucket = outgoing.get(edge.from) ?? [];
493
- bucket.push(edge);
494
- outgoing.set(edge.from, bucket);
495
- }
496
-
497
- return {
498
- nodesById,
499
- outgoingEdges: outgoing,
500
- };
501
- }
502
-
503
- function readEvidenceNode(
504
- snapshot: ObservedLocalHistoryGraphSnapshot,
505
- nodeId: string,
506
- ): Evidence | null {
507
- const node = snapshot.nodesById.get(nodeId);
508
- if (node === undefined || asString(node.props["entityKind"]) !== "evidence") {
509
- return null;
510
- }
511
- const parsed = evidenceSchema.safeParse({
512
- evidenceId: asString(node.props["evidenceId"]),
513
- evidenceKind: asString(node.props["evidenceKind"]),
514
- source: asString(node.props["source"]),
515
- capturedAt: asString(node.props["capturedAt"]),
516
- strength: asString(node.props["strength"]),
517
- details: asUnknownRecord(node.props["details"]) ?? {},
518
- });
519
- return parsed.success ? parsed.data : null;
520
- }
521
-
522
- function readActorNode(
523
- snapshot: ObservedLocalHistoryGraphSnapshot,
524
- nodeId: string,
525
- ): Actor | null {
526
- const node = snapshot.nodesById.get(nodeId);
527
- if (node === undefined || asString(node.props["entityKind"]) !== "actor") {
528
- return null;
529
- }
530
- const parsed = actorSchema.safeParse({
531
- actorId: asString(node.props["actorId"]),
532
- actorKind: asString(node.props["actorKind"]),
533
- displayName: asString(node.props["displayName"]),
534
- source: asString(node.props["source"]),
535
- authorityScope: asString(node.props["authorityScope"]),
536
- });
537
- return parsed.success ? parsed.data : null;
538
- }
539
-
540
- function readFootprint(
541
- snapshot: ObservedLocalHistoryGraphSnapshot,
542
- eventNodeId: string,
543
- ): CausalFootprint {
544
- const footprintNodeId = outgoingTargets(snapshot, eventNodeId, "has_footprint")[0];
545
- const footprintNode = footprintNodeId === undefined ? undefined : snapshot.nodesById.get(footprintNodeId);
546
- const regions = (footprintNodeId === undefined ? [] : outgoingTargets(snapshot, footprintNodeId, "has_region"))
547
- .map((regionNodeId) => {
548
- const regionNode = snapshot.nodesById.get(regionNodeId);
549
- if (regionNode === undefined) {
550
- return null;
551
- }
552
- const parsed = causalRegionSchema.safeParse({
553
- path: asString(regionNode.props["path"]),
554
- startLine: regionNode.props["startLine"],
555
- endLine: regionNode.props["endLine"],
556
- });
557
- return parsed.success ? parsed.data : null;
558
- })
559
- .filter((region): region is z.infer<typeof causalRegionSchema> => region !== null);
560
-
561
- const parsed = causalFootprintSchema.safeParse({
562
- paths: footprintNode === undefined ? [] : asStringArray(footprintNode.props["paths"]) ?? [],
563
- symbols: footprintNode === undefined ? [] : asStringArray(footprintNode.props["symbols"]) ?? [],
564
- regions,
565
- });
566
- if (parsed.success) {
567
- return parsed.data;
568
- }
569
- return {
570
- paths: [],
571
- symbols: [],
572
- regions: [],
573
- };
574
- }
575
-
576
- function readSupportedEvidence(
577
- snapshot: ObservedLocalHistoryGraphSnapshot,
578
- eventNodeId: string,
579
- ): Evidence[] {
580
- return sortEvidence(
581
- outgoingTargets(snapshot, eventNodeId, "supported_by")
582
- .map((nodeId) => readEvidenceNode(snapshot, nodeId))
583
- .filter((evidence): evidence is Evidence => evidence !== null),
584
- );
585
- }
586
-
587
- function readEventAttribution(
588
- snapshot: ObservedLocalHistoryGraphSnapshot,
589
- eventNode: ObservedLocalHistoryNode,
590
- input: {
591
- readonly continuityOperation?: LocalHistoryContinuityOperation | undefined;
592
- readonly evidence: readonly Evidence[];
593
- },
594
- ): AttributionSummary {
595
- if (input.continuityOperation !== undefined) {
596
- return deriveContinuityAttribution(input.continuityOperation, input.evidence);
597
- }
598
-
599
- const actorNodeId = outgoingTargets(snapshot, eventNode.id, "attributed_to")[0];
600
- const actor = actorNodeId === undefined ? null : readActorNode(snapshot, actorNodeId);
601
- const parsed = attributionSummarySchema.safeParse({
602
- actor: actor ?? buildUnknownAttributionForActorId(asString(eventNode.props["actorId"])).actor,
603
- confidence: asString(eventNode.props["attributionConfidence"]) ?? "unknown",
604
- basis: asString(eventNode.props["attributionBasis"]) ?? "unknown_fallback",
605
- evidence: [...input.evidence],
606
- });
607
- return parsed.success ? parsed.data : buildUnknownAttributionForActorId(asString(eventNode.props["actorId"]));
608
- }
609
-
610
- function readContinuityRecordFromGraph(
611
- snapshot: ObservedLocalHistoryGraphSnapshot,
612
- node: ObservedLocalHistoryNode,
613
- ): ContinuityRecord | null {
614
- if (
615
- asString(node.props["entityKind"]) !== "local_history_event" ||
616
- asString(node.props["eventKind"]) !== "continuity"
617
- ) {
618
- return null;
619
- }
620
- const operation = localHistoryContinuityOperationSchema.safeParse(asString(node.props["continuityOperation"]));
621
- const repoId = asString(node.props["repoId"]);
622
- const worktreeId = asString(node.props["worktreeId"]);
623
- const recordId = asString(node.props["eventId"]);
624
- const occurredAt = asString(node.props["occurredAt"]);
625
- const continuityEvidence = readSupportedEvidence(snapshot, node.id);
626
- if (!operation.success || repoId === undefined || worktreeId === undefined || recordId === undefined || occurredAt === undefined) {
627
- return null;
628
- }
629
- const parsed = continuityRecordSchema.safeParse({
630
- recordId,
631
- continuityKey: asString(node.props["continuityKey"]) ?? buildContinuityKey(repoId, worktreeId),
632
- operation: operation.data,
633
- repoId,
634
- worktreeId,
635
- transportSessionId: asString(node.props["transportSessionId"]),
636
- workspaceSliceId: asString(node.props["workspaceSliceId"]),
637
- causalSessionId: asString(node.props["causalSessionId"]),
638
- strandId: asString(node.props["strandId"]),
639
- checkoutEpochId: asString(node.props["checkoutEpochId"]),
640
- workspaceOverlayId: asNullableString(node.props["workspaceOverlayId"]) ?? null,
641
- occurredAt,
642
- continuedFromRecordId: asNullableString(node.props["continuedFromEventId"]) ?? null,
643
- continuedFromCausalSessionId: asNullableString(node.props["continuedFromCausalSessionId"]) ?? null,
644
- continuedFromStrandId: asNullableString(node.props["continuedFromStrandId"]) ?? null,
645
- continuityConfidence: asString(node.props["attributionConfidence"]) ?? "unknown",
646
- continuityEvidence,
647
- attribution: readEventAttribution(snapshot, node, {
648
- continuityOperation: operation.data,
649
- evidence: continuityEvidence,
650
- }),
651
- });
652
- return parsed.success ? parsed.data : null;
653
- }
654
-
655
- function readReadEventFromGraph(
656
- snapshot: ObservedLocalHistoryGraphSnapshot,
657
- node: ObservedLocalHistoryNode,
658
- ): Extract<CausalEvent, { eventKind: "read" }> | null {
659
- if (asString(node.props["entityKind"]) !== "local_history_event" || asString(node.props["eventKind"]) !== "read") {
660
- return null;
661
- }
662
- const evidence = readSupportedEvidence(snapshot, node.id);
663
- const parsed = readEventSchema.safeParse({
664
- eventId: asString(node.props["eventId"]),
665
- eventKind: "read",
666
- repoId: asString(node.props["repoId"]),
667
- worktreeId: asString(node.props["worktreeId"]),
668
- checkoutEpochId: asString(node.props["checkoutEpochId"]),
669
- workspaceOverlayId: asNullableString(node.props["workspaceOverlayId"]) ?? null,
670
- transportSessionId: asString(node.props["transportSessionId"]),
671
- workspaceSliceId: asString(node.props["workspaceSliceId"]),
672
- causalSessionId: asString(node.props["causalSessionId"]),
673
- strandId: asString(node.props["strandId"]),
674
- actorId: asString(node.props["actorId"]) ?? "unknown",
675
- confidence: asString(node.props["attributionConfidence"]) ?? "unknown",
676
- evidenceIds: evidence.map((item) => item.evidenceId),
677
- attribution: readEventAttribution(snapshot, node, { evidence }),
678
- footprint: readFootprint(snapshot, node.id),
679
- occurredAt: asString(node.props["occurredAt"]),
680
- payload: {
681
- surface: asString(node.props["surface"]),
682
- projection: asString(node.props["projection"]),
683
- sourceLayer: asString(node.props["sourceLayer"]),
684
- reason: asString(node.props["reason"]),
685
- },
686
- });
687
- return parsed.success ? parsed.data : null;
688
- }
689
-
690
- function readStageEventFromGraph(
691
- snapshot: ObservedLocalHistoryGraphSnapshot,
692
- node: ObservedLocalHistoryNode,
693
- ): Extract<CausalEvent, { eventKind: "stage" }> | null {
694
- if (asString(node.props["entityKind"]) !== "local_history_event" || asString(node.props["eventKind"]) !== "stage") {
695
- return null;
696
- }
697
- const evidence = readSupportedEvidence(snapshot, node.id);
698
- const footprint = readFootprint(snapshot, node.id);
699
- const parsed = stageEventSchema.safeParse({
700
- eventId: asString(node.props["eventId"]),
701
- eventKind: "stage",
702
- repoId: asString(node.props["repoId"]),
703
- worktreeId: asString(node.props["worktreeId"]),
704
- checkoutEpochId: asString(node.props["checkoutEpochId"]),
705
- workspaceOverlayId: asNullableString(node.props["workspaceOverlayId"]) ?? null,
706
- transportSessionId: asString(node.props["transportSessionId"]),
707
- workspaceSliceId: asString(node.props["workspaceSliceId"]),
708
- causalSessionId: asString(node.props["causalSessionId"]),
709
- strandId: asString(node.props["strandId"]),
710
- actorId: asString(node.props["actorId"]) ?? "unknown",
711
- confidence: asString(node.props["attributionConfidence"]) ?? "unknown",
712
- evidenceIds: evidence.map((item) => item.evidenceId),
713
- attribution: readEventAttribution(snapshot, node, { evidence }),
714
- footprint,
715
- occurredAt: asString(node.props["occurredAt"]),
716
- payload: {
717
- targetId: asString(node.props["targetId"]),
718
- footprint,
719
- selectionKind: asString(node.props["selectionKind"]),
720
- },
721
- });
722
- return parsed.success ? parsed.data : null;
723
- }
724
-
725
- function readTransitionEventFromGraph(
726
- snapshot: ObservedLocalHistoryGraphSnapshot,
727
- node: ObservedLocalHistoryNode,
728
- ): Extract<CausalEvent, { eventKind: "transition" }> | null {
729
- if (
730
- asString(node.props["entityKind"]) !== "local_history_event" ||
731
- asString(node.props["eventKind"]) !== "transition"
732
- ) {
733
- return null;
734
- }
735
- const evidence = readSupportedEvidence(snapshot, node.id);
736
- const parsed = transitionEventSchema.safeParse({
737
- eventId: asString(node.props["eventId"]),
738
- eventKind: "transition",
739
- repoId: asString(node.props["repoId"]),
740
- worktreeId: asString(node.props["worktreeId"]),
741
- checkoutEpochId: asString(node.props["checkoutEpochId"]),
742
- workspaceOverlayId: asNullableString(node.props["workspaceOverlayId"]) ?? null,
743
- transportSessionId: asString(node.props["transportSessionId"]),
744
- workspaceSliceId: asString(node.props["workspaceSliceId"]),
745
- causalSessionId: asString(node.props["causalSessionId"]),
746
- strandId: asString(node.props["strandId"]),
747
- actorId: asString(node.props["actorId"]) ?? "unknown",
748
- confidence: asString(node.props["attributionConfidence"]) ?? "unknown",
749
- evidenceIds: evidence.map((item) => item.evidenceId),
750
- attribution: readEventAttribution(snapshot, node, { evidence }),
751
- footprint: readFootprint(snapshot, node.id),
752
- occurredAt: asString(node.props["occurredAt"]),
753
- payload: {
754
- semanticKind: asString(node.props["semanticKind"]),
755
- authority: asString(node.props["authority"]),
756
- phase: asNullableString(node.props["phase"]) ?? null,
757
- summary: asString(node.props["summary"]),
758
- transitionKind: asNullableString(node.props["transitionKind"]) ?? null,
759
- fromRef: asNullableString(node.props["fromRef"]) ?? null,
760
- toRef: asNullableString(node.props["toRef"]) ?? null,
761
- createdCheckoutEpochId: asNullableString(node.props["createdCheckoutEpochId"]) ?? null,
762
- },
763
- });
764
- return parsed.success ? parsed.data : null;
765
- }
766
-
767
- function loadStateFromGraphSnapshot(
768
- snapshot: ObservedLocalHistoryGraphSnapshot,
769
- repoId: string,
770
- worktreeId: string,
771
- ): ContinuityState | null {
772
- const continuityRecords = sortContinuityRecords(
773
- [...snapshot.nodesById.values()]
774
- .map((node) => readContinuityRecordFromGraph(snapshot, node))
775
- .filter((record): record is ContinuityRecord =>
776
- record !== null && record.repoId === repoId && record.worktreeId === worktreeId
777
- ),
778
- );
779
-
780
- const readEvents = sortEvents(
781
- [...snapshot.nodesById.values()]
782
- .map((node) => readReadEventFromGraph(snapshot, node))
783
- .filter((event): event is Extract<CausalEvent, { eventKind: "read" }> =>
784
- event !== null && event.repoId === repoId && event.worktreeId === worktreeId
785
- ),
786
- );
787
- const stageEvents = sortEvents(
788
- [...snapshot.nodesById.values()]
789
- .map((node) => readStageEventFromGraph(snapshot, node))
790
- .filter((event): event is Extract<CausalEvent, { eventKind: "stage" }> =>
791
- event !== null && event.repoId === repoId && event.worktreeId === worktreeId
792
- ),
793
- );
794
- const transitionEvents = sortEvents(
795
- [...snapshot.nodesById.values()]
796
- .map((node) => readTransitionEventFromGraph(snapshot, node))
797
- .filter((event): event is Extract<CausalEvent, { eventKind: "transition" }> =>
798
- event !== null && event.repoId === repoId && event.worktreeId === worktreeId
799
- ),
800
- );
801
-
802
- if (
803
- continuityRecords.length === 0 &&
804
- readEvents.length === 0 &&
805
- stageEvents.length === 0 &&
806
- transitionEvents.length === 0
807
- ) {
808
- return null;
809
- }
810
-
811
- const lastRecord = continuityRecords.at(-1) ?? null;
812
- return {
813
- continuityKey: lastRecord?.continuityKey ?? buildContinuityKey(repoId, worktreeId),
814
- repoId,
815
- worktreeId,
816
- activeRecordId: lastRecord === null || lastRecord.operation === "park" ? null : lastRecord.recordId,
817
- records: continuityRecords,
818
- readEvents,
819
- stageEvents,
820
- transitionEvents,
821
- };
822
- }
823
-
824
- async function loadStateFromGraph(
825
- graph: PersistedLocalHistoryGraphContext | null | undefined,
826
- repoId: string,
827
- worktreeId: string,
828
- ): Promise<ContinuityState | null> {
829
- const snapshot = await loadObservedLocalHistoryGraph(graph);
830
- if (snapshot === null) {
831
- return null;
832
- }
833
- return loadStateFromGraphSnapshot(snapshot, repoId, worktreeId);
834
- }
835
-
836
- async function loadStatesForRepoFromGraph(
837
- graph: PersistedLocalHistoryGraphContext | null | undefined,
838
- repoId: string,
839
- ): Promise<ContinuityState[] | null> {
840
- const snapshot = await loadObservedLocalHistoryGraph(graph);
841
- if (snapshot === null) {
842
- return null;
843
- }
844
-
845
- const worktreeIds = new Set(
846
- [...snapshot.nodesById.values()]
847
- .filter((node) => asString(node.props["repoId"]) === repoId)
848
- .map((node) => asString(node.props["worktreeId"]))
849
- .filter((value): value is string => value !== undefined),
850
- );
851
-
852
- const states = [...worktreeIds]
853
- .map((worktreeId) => loadStateFromGraphSnapshot(snapshot, repoId, worktreeId))
854
- .filter((state): state is ContinuityState => state !== null);
855
-
856
- return states.length > 0 ? states : null;
857
- }
858
-
859
- interface LegacyPersistedLocalHistoryArtifact {
860
- readonly filePath: string;
861
- readonly state: ContinuityState;
862
- }
863
-
864
- export interface PersistedLocalHistoryMigrationResult {
865
- graftDir: string;
866
- discoveredArtifacts: number;
867
- migratedArtifacts: number;
868
- malformedArtifacts: number;
869
- importedContinuityRecords: number;
870
- importedReadEvents: number;
871
- importedStageEvents: number;
872
- importedTransitionEvents: number;
873
- skippedContinuityRecords: number;
874
- skippedReadEvents: number;
875
- skippedStageEvents: number;
876
- skippedTransitionEvents: number;
877
- }
878
-
879
- async function loadLegacyPersistedLocalHistoryArtifacts(input: {
880
- readonly fs: FileSystem;
881
- readonly codec: JsonCodec;
882
- readonly graftDir: string;
883
- }): Promise<{
884
- readonly artifacts: readonly LegacyPersistedLocalHistoryArtifact[];
885
- readonly malformedArtifacts: number;
886
- }> {
887
- const historyDir = path.join(input.graftDir, "local-history");
888
- let filenames: string[];
889
- try {
890
- filenames = await input.fs.readdir(historyDir);
891
- } catch {
892
- return {
893
- artifacts: [],
894
- malformedArtifacts: 0,
895
- };
896
- }
897
-
898
- const artifacts: LegacyPersistedLocalHistoryArtifact[] = [];
899
- let malformedArtifacts = 0;
900
-
901
- for (const filename of filenames) {
902
- if (!filename.endsWith(".json")) {
903
- continue;
904
- }
905
- const filePath = path.join(historyDir, filename);
906
- try {
907
- const raw = await input.fs.readFile(filePath, "utf-8");
908
- const state = continuityStateSchema.parse(input.codec.decode(raw));
909
- artifacts.push({ filePath, state });
910
- } catch {
911
- malformedArtifacts += 1;
912
- }
913
- }
914
-
915
- return {
916
- artifacts,
917
- malformedArtifacts,
918
- };
919
- }
920
-
921
- function buildLegacyMigrationSequence(state: ContinuityState): {
922
- readonly kind: "continuity" | "read" | "stage" | "transition";
923
- readonly occurredAt: string;
924
- readonly sequence: number;
925
- readonly id: string;
926
- readonly record?: ContinuityRecord;
927
- readonly event?: Extract<CausalEvent, { eventKind: "read" | "stage" | "transition" }>;
928
- }[] {
929
- const sequence = [
930
- ...state.records.map((record, sequenceIndex) => ({
931
- kind: "continuity" as const,
932
- occurredAt: record.occurredAt,
933
- sequence: sequenceIndex,
934
- id: record.recordId,
935
- record,
936
- })),
937
- ...state.readEvents.map((event, sequenceIndex) => ({
938
- kind: "read" as const,
939
- occurredAt: event.occurredAt,
940
- sequence: sequenceIndex,
941
- id: event.eventId,
942
- event,
943
- })),
944
- ...state.stageEvents.map((event, sequenceIndex) => ({
945
- kind: "stage" as const,
946
- occurredAt: event.occurredAt,
947
- sequence: sequenceIndex,
948
- id: event.eventId,
949
- event,
950
- })),
951
- ...state.transitionEvents.map((event, sequenceIndex) => ({
952
- kind: "transition" as const,
953
- occurredAt: event.occurredAt,
954
- sequence: sequenceIndex,
955
- id: event.eventId,
956
- event,
957
- })),
958
- ];
959
-
960
- const priority = { continuity: 0, read: 1, stage: 2, transition: 3 } as const;
961
-
962
- return sequence.sort((left, right) => {
963
- const byTime = left.occurredAt.localeCompare(right.occurredAt);
964
- if (byTime !== 0) {
965
- return byTime;
966
- }
967
- const byPriority = priority[left.kind] - priority[right.kind];
968
- if (byPriority !== 0) {
969
- return byPriority;
970
- }
971
- const bySequence = left.sequence - right.sequence;
972
- if (bySequence !== 0) {
973
- return bySequence;
974
- }
975
- return left.id.localeCompare(right.id);
976
- });
977
- }
978
-
979
- async function hasLocalHistoryEventNode(
980
- graph: PersistedLocalHistoryGraphContext,
981
- eventId: string,
982
- ): Promise<boolean> {
983
- return graph.warp.hasNode(`lh:event:${eventId}`);
984
- }
985
-
986
- export async function migrateLegacyPersistedLocalHistoryToGraph(input: {
987
- readonly fs: FileSystem;
988
- readonly codec: JsonCodec;
989
- readonly graftDir: string;
990
- readonly graph: PersistedLocalHistoryGraphContext;
991
- }): Promise<PersistedLocalHistoryMigrationResult> {
992
- const { artifacts, malformedArtifacts } = await loadLegacyPersistedLocalHistoryArtifacts(input);
993
- const result: PersistedLocalHistoryMigrationResult = {
994
- graftDir: input.graftDir,
995
- discoveredArtifacts: artifacts.length,
996
- migratedArtifacts: 0,
997
- malformedArtifacts,
998
- importedContinuityRecords: 0,
999
- importedReadEvents: 0,
1000
- importedStageEvents: 0,
1001
- importedTransitionEvents: 0,
1002
- skippedContinuityRecords: 0,
1003
- skippedReadEvents: 0,
1004
- skippedStageEvents: 0,
1005
- skippedTransitionEvents: 0,
1006
- };
1007
-
1008
- for (const artifact of artifacts) {
1009
- const importedState = createEmptyState(
1010
- artifact.state.continuityKey,
1011
- artifact.state.repoId,
1012
- artifact.state.worktreeId,
1013
- );
1014
-
1015
- for (const item of buildLegacyMigrationSequence(artifact.state)) {
1016
- if (item.kind === "continuity" && item.record !== undefined) {
1017
- const previousEventId = findLatestEventIdForStrand(importedState, item.record.strandId);
1018
- if (await hasLocalHistoryEventNode(input.graph, item.record.recordId)) {
1019
- result.skippedContinuityRecords += 1;
1020
- } else {
1021
- await writeContinuityRecordToGraph(input.graph, {
1022
- record: item.record,
1023
- previousEventId,
1024
- });
1025
- result.importedContinuityRecords += 1;
1026
- }
1027
- importedState.records.push(item.record);
1028
- if (artifact.state.activeRecordId === item.record.recordId) {
1029
- importedState.activeRecordId = item.record.recordId;
1030
- }
1031
- continue;
1032
- }
1033
-
1034
- if (item.event === undefined) {
1035
- continue;
1036
- }
1037
-
1038
- const previousEventId = item.event.strandId === null
1039
- ? null
1040
- : findLatestEventIdForStrand(importedState, item.event.strandId);
1041
- if (await hasLocalHistoryEventNode(input.graph, item.event.eventId)) {
1042
- if (item.kind === "read") result.skippedReadEvents += 1;
1043
- if (item.kind === "stage") result.skippedStageEvents += 1;
1044
- if (item.kind === "transition") result.skippedTransitionEvents += 1;
1045
- } else {
1046
- await writeCausalEventToGraph(input.graph, {
1047
- event: item.event,
1048
- previousEventId,
1049
- });
1050
- if (item.kind === "read") result.importedReadEvents += 1;
1051
- if (item.kind === "stage") result.importedStageEvents += 1;
1052
- if (item.kind === "transition") result.importedTransitionEvents += 1;
1053
- }
1054
-
1055
- if (item.kind === "read") {
1056
- importedState.readEvents.push(item.event as Extract<CausalEvent, { eventKind: "read" }>);
1057
- } else if (item.kind === "stage") {
1058
- importedState.stageEvents.push(item.event as Extract<CausalEvent, { eventKind: "stage" }>);
1059
- } else {
1060
- importedState.transitionEvents.push(item.event as Extract<CausalEvent, { eventKind: "transition" }>);
1061
- }
1062
- }
1063
-
1064
- result.migratedArtifacts += 1;
1065
- }
1066
-
1067
- return result;
1068
- }
1069
-
1070
- export class PersistedLocalHistoryStore {
1071
- constructor(
1072
- private readonly deps: {
1073
- readonly fs: FileSystem;
1074
- readonly codec: JsonCodec;
1075
- readonly graftDir: string;
1076
- },
1077
- ) {}
1078
-
1079
- async noteBinding(input: {
1080
- readonly current: PersistedLocalHistoryContext;
1081
- readonly previous?: PersistedLocalHistoryContext | null;
1082
- readonly currentGraph?: PersistedLocalHistoryGraphContext | null;
1083
- readonly previousGraph?: PersistedLocalHistoryGraphContext | null;
1084
- }): Promise<void> {
1085
- const previous = input.previous ?? null;
1086
- const currentKey = buildContinuityKey(input.current.repoId, input.current.worktreeId);
1087
-
1088
- if (previous !== null && input.previousGraph !== null && input.previousGraph !== undefined) {
1089
- const previousKey = buildContinuityKey(previous.repoId, previous.worktreeId);
1090
- if (previousKey !== currentKey) {
1091
- const previousState = await this.loadWritableState(
1092
- input.previousGraph,
1093
- previousKey,
1094
- previous.repoId,
1095
- previous.worktreeId,
1096
- );
1097
- const previousActive = findRecord(previousState, previousState.activeRecordId);
1098
- if (previousActive !== null) {
1099
- const parkRecord = createContinuityRecord({
1100
- operation: "park",
1101
- continuityKey: previousKey,
1102
- context: previous,
1103
- previous: previousActive,
1104
- });
1105
- const previousEventId = findLatestEventIdForStrand(previousState, previous.strandId);
1106
- appendRecord(
1107
- previousState,
1108
- parkRecord,
1109
- false,
1110
- );
1111
- await writeContinuityRecordToGraph(input.previousGraph, {
1112
- record: parkRecord,
1113
- previousEventId,
1114
- });
1115
- }
1116
- }
1117
- }
1118
-
1119
- const currentState = await this.loadWritableState(
1120
- input.currentGraph,
1121
- currentKey,
1122
- input.current.repoId,
1123
- input.current.worktreeId,
1124
- );
1125
- const previousCurrentActive = findRecord(currentState, currentState.activeRecordId);
1126
- let latestCurrentEventId = findLatestEventIdForStrand(currentState, input.current.strandId);
1127
- if (previousCurrentActive !== null) {
1128
- const parkRecord = createContinuityRecord({
1129
- operation: "park",
1130
- continuityKey: currentKey,
1131
- context: input.current,
1132
- previous: previousCurrentActive,
1133
- });
1134
- const parkPreviousEventId = latestCurrentEventId;
1135
- appendRecord(
1136
- currentState,
1137
- parkRecord,
1138
- false,
1139
- );
1140
- if (parkRecord.strandId === input.current.strandId) {
1141
- latestCurrentEventId = parkRecord.recordId;
1142
- }
1143
- if (input.currentGraph !== null && input.currentGraph !== undefined) {
1144
- await writeContinuityRecordToGraph(input.currentGraph, {
1145
- record: parkRecord,
1146
- previousEventId: parkPreviousEventId,
1147
- });
1148
- }
1149
- }
1150
-
1151
- const operation = classifyContinuityOperation(previousCurrentActive, input.current);
1152
- const currentRecord = createContinuityRecord({
1153
- operation,
1154
- continuityKey: currentKey,
1155
- context: input.current,
1156
- previous: previousCurrentActive,
1157
- });
1158
- appendRecord(
1159
- currentState,
1160
- currentRecord,
1161
- true,
1162
- );
1163
- if (input.currentGraph !== null && input.currentGraph !== undefined) {
1164
- await writeContinuityRecordToGraph(input.currentGraph, {
1165
- record: currentRecord,
1166
- previousEventId: latestCurrentEventId,
1167
- });
1168
- }
1169
- }
1170
-
1171
- async noteCheckoutBoundary(input: {
1172
- readonly previous: PersistedLocalHistoryContext;
1173
- readonly current: PersistedLocalHistoryContext;
1174
- readonly graph?: PersistedLocalHistoryGraphContext | null;
1175
- }): Promise<void> {
1176
- const continuityKey = buildContinuityKey(input.current.repoId, input.current.worktreeId);
1177
- const state = await this.loadWritableState(
1178
- input.graph,
1179
- continuityKey,
1180
- input.current.repoId,
1181
- input.current.worktreeId,
1182
- );
1183
- const activeRecord = findRecord(state, state.activeRecordId);
1184
- const baseRecord = activeRecord ?? state.records.at(-1) ?? null;
1185
- if (baseRecord === null) {
1186
- const startRecord = createContinuityRecord({
1187
- operation: "start",
1188
- continuityKey,
1189
- context: input.current,
1190
- previous: null,
1191
- });
1192
- appendRecord(
1193
- state,
1194
- startRecord,
1195
- true,
1196
- );
1197
- if (input.graph !== null && input.graph !== undefined) {
1198
- await writeContinuityRecordToGraph(input.graph, {
1199
- record: startRecord,
1200
- previousEventId: null,
1201
- });
1202
- }
1203
- return;
1204
- }
1205
- if (baseRecord.checkoutEpochId === input.current.checkoutEpochId) {
1206
- return;
1207
- }
1208
-
1209
- const transitionEvidence = buildGitTransitionEvidence("fork", input.current);
1210
- const parkPreviousEventId = findLatestEventIdForStrand(state, input.previous.strandId);
1211
- const parkRecord = createContinuityRecord({
1212
- operation: "park",
1213
- continuityKey,
1214
- context: { ...input.previous, observedAt: input.current.observedAt },
1215
- previous: baseRecord,
1216
- additionalEvidence: transitionEvidence,
1217
- });
1218
- appendRecord(
1219
- state,
1220
- parkRecord,
1221
- false,
1222
- );
1223
- const forkRecord = createContinuityRecord({
1224
- operation: "fork",
1225
- continuityKey,
1226
- context: input.current,
1227
- previous: baseRecord,
1228
- additionalEvidence: transitionEvidence,
1229
- });
1230
- appendRecord(
1231
- state,
1232
- forkRecord,
1233
- true,
1234
- );
1235
- if (input.graph !== null && input.graph !== undefined) {
1236
- await writeContinuityRecordToGraph(input.graph, {
1237
- record: parkRecord,
1238
- previousEventId: parkPreviousEventId,
1239
- });
1240
- await writeContinuityRecordToGraph(input.graph, {
1241
- record: forkRecord,
1242
- previousEventId: null,
1243
- });
1244
- }
1245
- }
1246
-
1247
- async summarize(
1248
- status: WorkspaceStatus,
1249
- causalContext: RuntimeCausalContext,
1250
- graph?: PersistedLocalHistoryGraphContext | null,
1251
- ): Promise<PersistedLocalHistorySummary> {
1252
- if (status.repoId === null || status.worktreeId === null) {
1253
- return emptyPersistedLocalHistorySummary({
1254
- preserves: PERSISTED_LOCAL_HISTORY_PRESERVES,
1255
- excludes: PERSISTED_LOCAL_HISTORY_EXCLUDES,
1256
- });
1257
- }
1258
-
1259
- const graphState = await loadStateFromGraph(graph, status.repoId, status.worktreeId);
1260
- if (graphState === null) {
1261
- return emptyPersistedLocalHistorySummary({
1262
- preserves: PERSISTED_LOCAL_HISTORY_PRESERVES,
1263
- excludes: PERSISTED_LOCAL_HISTORY_EXCLUDES,
1264
- });
1265
- }
1266
- return summarizeContinuityState({
1267
- state: graphState,
1268
- causalContext,
1269
- preserves: PERSISTED_LOCAL_HISTORY_PRESERVES,
1270
- excludes: PERSISTED_LOCAL_HISTORY_EXCLUDES,
1271
- });
1272
- }
1273
-
1274
- async summarizeRepoConcurrency(
1275
- status: WorkspaceStatus,
1276
- graph?: PersistedLocalHistoryGraphContext | null,
1277
- ): Promise<RepoConcurrencySummary | null> {
1278
- if (status.repoId === null || status.worktreeId === null) {
1279
- return null;
1280
- }
1281
-
1282
- const currentState = await loadStateFromGraph(graph, status.repoId, status.worktreeId);
1283
- if (currentState === null) {
1284
- return null;
1285
- }
1286
- const graphStates = await loadStatesForRepoFromGraph(graph, status.repoId);
1287
- const repoStates = graphStates ?? [currentState];
1288
-
1289
- return deriveRepoConcurrencySummary({
1290
- currentWorktreeId: status.worktreeId,
1291
- histories: [
1292
- toRepoConcurrencyWorktreeHistory(currentState),
1293
- ...repoStates
1294
- .filter((state) => state.continuityKey !== currentState.continuityKey)
1295
- .map((state) => toRepoConcurrencyWorktreeHistory(state)),
1296
- ],
1297
- });
1298
- }
1299
-
1300
- async listRecentActivity(
1301
- status: WorkspaceStatus,
1302
- causalContext: RuntimeCausalContext,
1303
- limit: number,
1304
- graph?: PersistedLocalHistoryGraphContext | null,
1305
- ): Promise<PersistedLocalActivityWindow> {
1306
- if (status.repoId === null || status.worktreeId === null) {
1307
- return emptyPersistedLocalActivityWindow(limit);
1308
- }
1309
-
1310
- const graphState = await loadStateFromGraph(graph, status.repoId, status.worktreeId);
1311
- if (graphState === null) {
1312
- return emptyPersistedLocalActivityWindow(limit);
1313
- }
1314
- return buildPersistedLocalActivityWindow({
1315
- state: graphState,
1316
- causalContext,
1317
- limit,
1318
- });
1319
- }
1320
-
1321
- async declareAttach(input: {
1322
- readonly current: PersistedLocalHistoryContext;
1323
- readonly declaration: PersistedLocalHistoryAttachDeclaration;
1324
- readonly graph?: PersistedLocalHistoryGraphContext | null;
1325
- }): Promise<void> {
1326
- const continuityKey = buildContinuityKey(input.current.repoId, input.current.worktreeId);
1327
- const state = await this.loadWritableState(
1328
- input.graph,
1329
- continuityKey,
1330
- input.current.repoId,
1331
- input.current.worktreeId,
1332
- );
1333
- const activeRecord = findRecord(state, state.activeRecordId);
1334
- const baseRecord = activeRecord ?? state.records.at(-1) ?? null;
1335
- if (baseRecord?.continuedFromRecordId === null || baseRecord === null) {
1336
- throw new PersistedLocalHistoryAttachUnavailableError();
1337
- }
1338
-
1339
- const attachRecord = createContinuityRecord({
1340
- operation: "attach",
1341
- continuityKey,
1342
- context: input.current,
1343
- previous: baseRecord,
1344
- additionalEvidence: buildAttachDeclarationEvidence(input.current, input.declaration),
1345
- });
1346
- appendRecord(
1347
- state,
1348
- attachRecord,
1349
- true,
1350
- );
1351
- if (input.graph !== null && input.graph !== undefined) {
1352
- const previousEventId = findLatestEventIdForStrand(
1353
- {
1354
- ...state,
1355
- records: state.records.slice(0, -1),
1356
- },
1357
- input.current.strandId,
1358
- );
1359
- await writeContinuityRecordToGraph(input.graph, {
1360
- record: attachRecord,
1361
- previousEventId,
1362
- });
1363
- }
1364
- }
1365
-
1366
- async declareSharedAttach(input: {
1367
- readonly current: PersistedLocalHistoryContext;
1368
- readonly declaration: PersistedLocalHistoryAttachDeclaration;
1369
- readonly source: PersistedLocalHistorySharedAttachSource;
1370
- readonly graph?: PersistedLocalHistoryGraphContext | null;
1371
- }): Promise<void> {
1372
- const continuityKey = buildContinuityKey(input.current.repoId, input.current.worktreeId);
1373
- const state = await this.loadWritableState(
1374
- input.graph,
1375
- continuityKey,
1376
- input.current.repoId,
1377
- input.current.worktreeId,
1378
- );
1379
- const baseRecord = findRecord(state, state.activeRecordId) ?? state.records.at(-1) ?? null;
1380
- if (baseRecord === null) {
1381
- throw new PersistedLocalHistoryAttachUnavailableError();
1382
- }
1383
-
1384
- const attachRecord = createContinuityRecord({
1385
- operation: "attach",
1386
- continuityKey,
1387
- context: input.current,
1388
- previous: baseRecord,
1389
- additionalEvidence: [
1390
- ...buildAttachDeclarationEvidence(input.current, input.declaration),
1391
- {
1392
- evidenceId: buildEvidenceId("attach", "daemon_session_observation", input.current, 400),
1393
- evidenceKind: "daemon_session_observation",
1394
- source: "daemon_control_plane.shared_attach",
1395
- capturedAt: input.current.observedAt,
1396
- strength: "strong",
1397
- details: {
1398
- sourceSessionId: input.source.sourceSessionId,
1399
- sourceCausalSessionId: input.source.causalSessionId,
1400
- sourceStrandId: input.source.strandId,
1401
- handoffKind: "cross_session_same_worktree",
1402
- },
1403
- },
1404
- ],
1405
- overrides: {
1406
- continuedFromCausalSessionId: input.source.causalSessionId,
1407
- continuedFromStrandId: input.source.strandId,
1408
- },
1409
- });
1410
- appendRecord(
1411
- state,
1412
- attachRecord,
1413
- true,
1414
- );
1415
- if (input.graph !== null && input.graph !== undefined) {
1416
- const previousEventId = findLatestEventIdForStrand(
1417
- {
1418
- ...state,
1419
- records: state.records.slice(0, -1),
1420
- },
1421
- input.current.strandId,
1422
- );
1423
- await writeContinuityRecordToGraph(input.graph, {
1424
- record: attachRecord,
1425
- previousEventId,
1426
- });
1427
- }
1428
- }
1429
-
1430
- async noteStageObservation(input: {
1431
- readonly current: PersistedLocalHistoryContext;
1432
- readonly stagedTarget: RuntimeStagedTargetFullFile;
1433
- readonly attribution: AttributionSummary;
1434
- readonly graph?: PersistedLocalHistoryGraphContext | null;
1435
- }): Promise<void> {
1436
- const continuityKey = buildContinuityKey(input.current.repoId, input.current.worktreeId);
1437
- const state = await this.loadWritableState(
1438
- input.graph,
1439
- continuityKey,
1440
- input.current.repoId,
1441
- input.current.worktreeId,
1442
- );
1443
- const event = createStageEvent(input.current, input.stagedTarget, input.attribution);
1444
- if (state.stageEvents.at(-1)?.eventId === event.eventId) {
1445
- return;
1446
- }
1447
- const previousEventId = findLatestEventIdForStrand(state, input.current.strandId);
1448
- state.stageEvents = keepRecent([...state.stageEvents, event], MAX_STAGE_EVENTS);
1449
- if (input.graph !== null && input.graph !== undefined) {
1450
- await writeCausalEventToGraph(input.graph, {
1451
- event,
1452
- previousEventId,
1453
- stagedTarget: input.stagedTarget,
1454
- });
1455
- }
1456
- }
1457
-
1458
- async noteReadObservation(input: {
1459
- readonly current: PersistedLocalHistoryContext;
1460
- readonly attribution: AttributionSummary;
1461
- readonly surface: string;
1462
- readonly projection: string;
1463
- readonly sourceLayer: SourceLayer;
1464
- readonly reason: string;
1465
- readonly footprint: CausalFootprint;
1466
- readonly graph?: PersistedLocalHistoryGraphContext | null;
1467
- }): Promise<void> {
1468
- const continuityKey = buildContinuityKey(input.current.repoId, input.current.worktreeId);
1469
- const state = await this.loadWritableState(
1470
- input.graph,
1471
- continuityKey,
1472
- input.current.repoId,
1473
- input.current.worktreeId,
1474
- );
1475
- const event = createReadEvent(input);
1476
- if (state.readEvents.at(-1)?.eventId === event.eventId) {
1477
- return;
1478
- }
1479
- const previousEventId = findLatestEventIdForStrand(state, input.current.strandId);
1480
- state.readEvents = keepRecent([...state.readEvents, event], MAX_READ_EVENTS);
1481
- if (input.graph !== null && input.graph !== undefined) {
1482
- await writeCausalEventToGraph(input.graph, {
1483
- event,
1484
- previousEventId,
1485
- });
1486
- }
1487
- }
1488
-
1489
- async noteSemanticTransitionObservation(input: {
1490
- readonly current: PersistedLocalHistoryContext;
1491
- readonly semanticTransition: NonNullable<RepoObservation["semanticTransition"]>;
1492
- readonly transition: RepoObservation["lastTransition"];
1493
- readonly attribution: AttributionSummary;
1494
- readonly graph?: PersistedLocalHistoryGraphContext | null;
1495
- }): Promise<void> {
1496
- const continuityKey = buildContinuityKey(input.current.repoId, input.current.worktreeId);
1497
- const state = await this.loadWritableState(
1498
- input.graph,
1499
- continuityKey,
1500
- input.current.repoId,
1501
- input.current.worktreeId,
1502
- );
1503
- const event = createTransitionEvent(input);
1504
- if (state.transitionEvents.at(-1)?.eventId === event.eventId) {
1505
- return;
1506
- }
1507
- const previousEventId = findLatestEventIdForStrand(state, input.current.strandId);
1508
- state.transitionEvents = keepRecent([...state.transitionEvents, event], MAX_TRANSITION_EVENTS);
1509
- if (input.graph !== null && input.graph !== undefined) {
1510
- await writeCausalEventToGraph(input.graph, {
1511
- event,
1512
- previousEventId,
1513
- });
1514
- }
1515
- }
1516
-
1517
- buildContext(
1518
- status: WorkspaceStatus,
1519
- causalContext: RuntimeCausalContext,
1520
- repoState: RepoObservation,
1521
- hookEvent: GitTransitionHookEvent | null = null,
1522
- ): PersistedLocalHistoryContext | null {
1523
- if (status.repoId === null || status.worktreeId === null) {
1524
- return null;
1525
- }
1526
- return {
1527
- repoId: status.repoId,
1528
- worktreeId: status.worktreeId,
1529
- transportSessionId: causalContext.transportSessionId,
1530
- workspaceSliceId: causalContext.workspaceSliceId,
1531
- causalSessionId: causalContext.causalSessionId,
1532
- strandId: causalContext.strandId,
1533
- checkoutEpochId: causalContext.checkoutEpochId,
1534
- workspaceOverlayId: repoState.workspaceOverlayId,
1535
- observedAt: repoState.observedAt,
1536
- warpWriterId: causalContext.warpWriterId,
1537
- transitionKind: repoState.lastTransition?.kind ?? null,
1538
- transitionReflogSubject: repoState.lastTransition?.evidence.reflogSubject ?? null,
1539
- hookTransitionName: hookEvent?.hookName ?? null,
1540
- hookTransitionArgs: hookEvent?.hookArgs ?? null,
1541
- hookTransitionObservedAt: hookEvent?.observedAt ?? null,
1542
- };
1543
- }
1544
-
1545
- private async loadWritableState(
1546
- graph: PersistedLocalHistoryGraphContext | null | undefined,
1547
- continuityKey: string,
1548
- repoId: string,
1549
- worktreeId: string,
1550
- ): Promise<ContinuityState> {
1551
- return await loadStateFromGraph(graph, repoId, worktreeId) ?? createEmptyState(continuityKey, repoId, worktreeId);
1552
- }
1553
- }
1554
-
1555
- function findLatestEventIdForStrand(state: ContinuityState, strandId: string): string | null {
1556
- const items: {
1557
- readonly id: string;
1558
- readonly occurredAt: string;
1559
- readonly priority: number;
1560
- readonly sequence: number;
1561
- }[] = [];
1562
-
1563
- for (const [index, record] of state.records.entries()) {
1564
- if (record.strandId === strandId) {
1565
- items.push({
1566
- id: record.recordId,
1567
- occurredAt: record.occurredAt,
1568
- priority: 0,
1569
- sequence: index,
1570
- });
1571
- }
1572
- }
1573
- for (const [index, event] of state.readEvents.entries()) {
1574
- if (event.strandId === strandId) {
1575
- items.push({
1576
- id: event.eventId,
1577
- occurredAt: event.occurredAt,
1578
- priority: 1,
1579
- sequence: index,
1580
- });
1581
- }
1582
- }
1583
- for (const [index, event] of state.stageEvents.entries()) {
1584
- if (event.strandId === strandId) {
1585
- items.push({
1586
- id: event.eventId,
1587
- occurredAt: event.occurredAt,
1588
- priority: 2,
1589
- sequence: index,
1590
- });
1591
- }
1592
- }
1593
- for (const [index, event] of state.transitionEvents.entries()) {
1594
- if (event.strandId === strandId) {
1595
- items.push({
1596
- id: event.eventId,
1597
- occurredAt: event.occurredAt,
1598
- priority: 3,
1599
- sequence: index,
1600
- });
1601
- }
1602
- }
1603
-
1604
- items.sort((left, right) => {
1605
- const byTime = left.occurredAt.localeCompare(right.occurredAt);
1606
- if (byTime !== 0) {
1607
- return byTime;
1608
- }
1609
- const byPriority = left.priority - right.priority;
1610
- if (byPriority !== 0) {
1611
- return byPriority;
1612
- }
1613
- const bySequence = left.sequence - right.sequence;
1614
- if (bySequence !== 0) {
1615
- return bySequence;
1616
- }
1617
- return left.id.localeCompare(right.id);
1618
- });
1619
-
1620
- return items.at(-1)?.id ?? null;
1621
- }