@flyingrobots/graft 0.5.0 → 0.6.0

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