@flyingrobots/graft 0.6.0 → 0.7.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 (563) hide show
  1. package/ADVANCED_GUIDE.md +52 -0
  2. package/CHANGELOG.md +142 -0
  3. package/GUIDE.md +53 -0
  4. package/README.md +1 -1
  5. package/dist/adapters/json-text-decoder.d.ts +3 -0
  6. package/dist/adapters/json-text-decoder.d.ts.map +1 -0
  7. package/dist/adapters/json-text-decoder.js +12 -0
  8. package/dist/adapters/json-text-decoder.js.map +1 -0
  9. package/dist/adapters/node-paths.d.ts +3 -0
  10. package/dist/adapters/node-paths.d.ts.map +1 -0
  11. package/dist/adapters/node-paths.js +29 -0
  12. package/dist/adapters/node-paths.js.map +1 -0
  13. package/dist/adapters/repo-paths.d.ts.map +1 -1
  14. package/dist/adapters/repo-paths.js +40 -5
  15. package/dist/adapters/repo-paths.js.map +1 -1
  16. package/dist/api/tool-bridge.d.ts +1 -1
  17. package/dist/api/tool-bridge.d.ts.map +1 -1
  18. package/dist/api/tool-bridge.js +1 -1
  19. package/dist/api/tool-bridge.js.map +1 -1
  20. package/dist/cli/cli-error.d.ts.map +1 -1
  21. package/dist/cli/cli-error.js +47 -10
  22. package/dist/cli/cli-error.js.map +1 -1
  23. package/dist/cli/command-parser.d.ts +12 -3
  24. package/dist/cli/command-parser.d.ts.map +1 -1
  25. package/dist/cli/command-parser.js +161 -2
  26. package/dist/cli/command-parser.js.map +1 -1
  27. package/dist/cli/daemon-status-model.d.ts +87 -0
  28. package/dist/cli/daemon-status-model.d.ts.map +1 -0
  29. package/dist/cli/daemon-status-model.js +142 -0
  30. package/dist/cli/daemon-status-model.js.map +1 -0
  31. package/dist/cli/daemon-status-render.d.ts +3 -0
  32. package/dist/cli/daemon-status-render.d.ts.map +1 -0
  33. package/dist/cli/daemon-status-render.js +100 -0
  34. package/dist/cli/daemon-status-render.js.map +1 -0
  35. package/dist/cli/daemon-status.d.ts +7 -0
  36. package/dist/cli/daemon-status.d.ts.map +1 -0
  37. package/dist/cli/daemon-status.js +79 -0
  38. package/dist/cli/daemon-status.js.map +1 -0
  39. package/dist/cli/git-graft-enhance-model.d.ts +67 -0
  40. package/dist/cli/git-graft-enhance-model.d.ts.map +1 -0
  41. package/dist/cli/git-graft-enhance-model.js +55 -0
  42. package/dist/cli/git-graft-enhance-model.js.map +1 -0
  43. package/dist/cli/git-graft-enhance-render.d.ts +3 -0
  44. package/dist/cli/git-graft-enhance-render.d.ts.map +1 -0
  45. package/dist/cli/git-graft-enhance-render.js +29 -0
  46. package/dist/cli/git-graft-enhance-render.js.map +1 -0
  47. package/dist/cli/git-graft-enhance.d.ts +14 -0
  48. package/dist/cli/git-graft-enhance.d.ts.map +1 -0
  49. package/dist/cli/git-graft-enhance.js +29 -0
  50. package/dist/cli/git-graft-enhance.js.map +1 -0
  51. package/dist/cli/index-cmd.d.ts.map +1 -1
  52. package/dist/cli/index-cmd.js +18 -21
  53. package/dist/cli/index-cmd.js.map +1 -1
  54. package/dist/cli/index-model.d.ts +5 -9
  55. package/dist/cli/index-model.d.ts.map +1 -1
  56. package/dist/cli/index-model.js +20 -18
  57. package/dist/cli/index-model.js.map +1 -1
  58. package/dist/cli/init-client-config.d.ts +12 -7
  59. package/dist/cli/init-client-config.d.ts.map +1 -1
  60. package/dist/cli/init-client-config.js +105 -43
  61. package/dist/cli/init-client-config.js.map +1 -1
  62. package/dist/cli/init-model.d.ts +9 -2
  63. package/dist/cli/init-model.d.ts.map +1 -1
  64. package/dist/cli/init-model.js +52 -4
  65. package/dist/cli/init-model.js.map +1 -1
  66. package/dist/cli/init-render.d.ts.map +1 -1
  67. package/dist/cli/init-render.js +2 -2
  68. package/dist/cli/init-render.js.map +1 -1
  69. package/dist/cli/init.d.ts.map +1 -1
  70. package/dist/cli/init.js +11 -9
  71. package/dist/cli/init.js.map +1 -1
  72. package/dist/cli/json-document.d.ts +5 -0
  73. package/dist/cli/json-document.d.ts.map +1 -1
  74. package/dist/cli/json-document.js +9 -0
  75. package/dist/cli/json-document.js.map +1 -1
  76. package/dist/cli/main.d.ts +7 -0
  77. package/dist/cli/main.d.ts.map +1 -1
  78. package/dist/cli/main.js +49 -7
  79. package/dist/cli/main.js.map +1 -1
  80. package/dist/cli/migrate-local-history.d.ts.map +1 -1
  81. package/dist/cli/migrate-local-history.js +3 -2
  82. package/dist/cli/migrate-local-history.js.map +1 -1
  83. package/dist/cli/peer-command.d.ts +1 -1
  84. package/dist/cli/peer-command.d.ts.map +1 -1
  85. package/dist/cli/peer-command.js +1 -1
  86. package/dist/cli/peer-command.js.map +1 -1
  87. package/dist/contracts/capabilities.d.ts +5 -5
  88. package/dist/contracts/capabilities.d.ts.map +1 -1
  89. package/dist/contracts/capabilities.js +89 -0
  90. package/dist/contracts/capabilities.js.map +1 -1
  91. package/dist/contracts/causal-ontology.d.ts +17 -17
  92. package/dist/contracts/json-object.d.ts +0 -1
  93. package/dist/contracts/json-object.d.ts.map +1 -1
  94. package/dist/contracts/json-object.js +0 -10
  95. package/dist/contracts/json-object.js.map +1 -1
  96. package/dist/contracts/output-schema-cli.d.ts +277 -25
  97. package/dist/contracts/output-schema-cli.d.ts.map +1 -1
  98. package/dist/contracts/output-schema-cli.js +35 -3
  99. package/dist/contracts/output-schema-cli.js.map +1 -1
  100. package/dist/contracts/output-schema-fragments.d.ts +212 -87
  101. package/dist/contracts/output-schema-fragments.d.ts.map +1 -1
  102. package/dist/contracts/output-schema-fragments.js +49 -2
  103. package/dist/contracts/output-schema-fragments.js.map +1 -1
  104. package/dist/contracts/output-schema-mcp.d.ts +372 -47
  105. package/dist/contracts/output-schema-mcp.d.ts.map +1 -1
  106. package/dist/contracts/output-schema-mcp.js +217 -1
  107. package/dist/contracts/output-schema-mcp.js.map +1 -1
  108. package/dist/contracts/output-schema-meta.d.ts +2 -2
  109. package/dist/contracts/output-schema-meta.d.ts.map +1 -1
  110. package/dist/contracts/output-schemas.d.ts +7 -7
  111. package/dist/contracts/output-schemas.d.ts.map +1 -1
  112. package/dist/contracts/output-schemas.js +294 -6
  113. package/dist/contracts/output-schemas.js.map +1 -1
  114. package/dist/git/diff.d.ts +11 -0
  115. package/dist/git/diff.d.ts.map +1 -1
  116. package/dist/git/diff.js +50 -6
  117. package/dist/git/diff.js.map +1 -1
  118. package/dist/mcp/burden.d.ts.map +1 -1
  119. package/dist/mcp/burden.js +9 -0
  120. package/dist/mcp/burden.js.map +1 -1
  121. package/dist/mcp/context.d.ts +3 -2
  122. package/dist/mcp/context.d.ts.map +1 -1
  123. package/dist/mcp/context.js +2 -37
  124. package/dist/mcp/context.js.map +1 -1
  125. package/dist/mcp/daemon-server.d.ts +2 -0
  126. package/dist/mcp/daemon-server.d.ts.map +1 -1
  127. package/dist/mcp/daemon-server.js +6 -1
  128. package/dist/mcp/daemon-server.js.map +1 -1
  129. package/dist/mcp/daemon-session-host.d.ts +1 -0
  130. package/dist/mcp/daemon-session-host.d.ts.map +1 -1
  131. package/dist/mcp/daemon-session-host.js +3 -0
  132. package/dist/mcp/daemon-session-host.js.map +1 -1
  133. package/dist/mcp/daemon-stdio-bridge.d.ts +1 -0
  134. package/dist/mcp/daemon-stdio-bridge.d.ts.map +1 -1
  135. package/dist/mcp/daemon-stdio-bridge.js +1 -0
  136. package/dist/mcp/daemon-stdio-bridge.js.map +1 -1
  137. package/dist/mcp/monitor-tick-job.d.ts +1 -0
  138. package/dist/mcp/monitor-tick-job.d.ts.map +1 -1
  139. package/dist/mcp/monitor-tick-job.js +84 -29
  140. package/dist/mcp/monitor-tick-job.js.map +1 -1
  141. package/dist/mcp/monitor-types.d.ts +1 -1
  142. package/dist/mcp/monitor-types.d.ts.map +1 -1
  143. package/dist/mcp/persisted-local-history-graph.d.ts +2 -2
  144. package/dist/mcp/persisted-local-history-graph.d.ts.map +1 -1
  145. package/dist/mcp/persisted-local-history-graph.js +3 -2
  146. package/dist/mcp/persisted-local-history-graph.js.map +1 -1
  147. package/dist/mcp/persisted-local-history.d.ts +5 -5
  148. package/dist/mcp/persisted-local-history.js +2 -2
  149. package/dist/mcp/persisted-local-history.js.map +1 -1
  150. package/dist/mcp/persistent-monitor-runtime.d.ts +1 -0
  151. package/dist/mcp/persistent-monitor-runtime.d.ts.map +1 -1
  152. package/dist/mcp/persistent-monitor-runtime.js +35 -0
  153. package/dist/mcp/persistent-monitor-runtime.js.map +1 -1
  154. package/dist/mcp/repo-tool-worker-context.d.ts.map +1 -1
  155. package/dist/mcp/repo-tool-worker-context.js +5 -2
  156. package/dist/mcp/repo-tool-worker-context.js.map +1 -1
  157. package/dist/mcp/server-context.d.ts.map +1 -1
  158. package/dist/mcp/server-context.js +13 -0
  159. package/dist/mcp/server-context.js.map +1 -1
  160. package/dist/mcp/server-tool-access.d.ts +1 -1
  161. package/dist/mcp/server-tool-access.d.ts.map +1 -1
  162. package/dist/mcp/server-tool-access.js +3 -1
  163. package/dist/mcp/server-tool-access.js.map +1 -1
  164. package/dist/mcp/server.d.ts +3 -0
  165. package/dist/mcp/server.d.ts.map +1 -1
  166. package/dist/mcp/server.js +5 -3
  167. package/dist/mcp/server.js.map +1 -1
  168. package/dist/mcp/tool-registry.d.ts.map +1 -1
  169. package/dist/mcp/tool-registry.js +18 -0
  170. package/dist/mcp/tool-registry.js.map +1 -1
  171. package/dist/mcp/tools/code-find.d.ts.map +1 -1
  172. package/dist/mcp/tools/code-find.js +20 -0
  173. package/dist/mcp/tools/code-find.js.map +1 -1
  174. package/dist/mcp/tools/code-show.d.ts.map +1 -1
  175. package/dist/mcp/tools/code-show.js +24 -0
  176. package/dist/mcp/tools/code-show.js.map +1 -1
  177. package/dist/mcp/tools/diagnostic-models.d.ts +2 -0
  178. package/dist/mcp/tools/diagnostic-models.d.ts.map +1 -1
  179. package/dist/mcp/tools/doctor.d.ts.map +1 -1
  180. package/dist/mcp/tools/doctor.js +18 -1
  181. package/dist/mcp/tools/doctor.js.map +1 -1
  182. package/dist/mcp/tools/export-surface-diff.d.ts +3 -0
  183. package/dist/mcp/tools/export-surface-diff.d.ts.map +1 -0
  184. package/dist/mcp/tools/export-surface-diff.js +24 -0
  185. package/dist/mcp/tools/export-surface-diff.js.map +1 -0
  186. package/dist/mcp/tools/file-outline.js +1 -1
  187. package/dist/mcp/tools/file-outline.js.map +1 -1
  188. package/dist/mcp/tools/graft-edit.d.ts +3 -0
  189. package/dist/mcp/tools/graft-edit.d.ts.map +1 -0
  190. package/dist/mcp/tools/graft-edit.js +192 -0
  191. package/dist/mcp/tools/graft-edit.js.map +1 -0
  192. package/dist/mcp/tools/knowledge-map.d.ts +3 -0
  193. package/dist/mcp/tools/knowledge-map.d.ts.map +1 -0
  194. package/dist/mcp/tools/knowledge-map.js +31 -0
  195. package/dist/mcp/tools/knowledge-map.js.map +1 -0
  196. package/dist/mcp/tools/monitor-nudge.d.ts +3 -0
  197. package/dist/mcp/tools/monitor-nudge.d.ts.map +1 -0
  198. package/dist/mcp/tools/monitor-nudge.js +17 -0
  199. package/dist/mcp/tools/monitor-nudge.js.map +1 -0
  200. package/dist/mcp/tools/precision-warp.d.ts +3 -3
  201. package/dist/mcp/tools/precision-warp.d.ts.map +1 -1
  202. package/dist/mcp/tools/precision-warp.js +24 -15
  203. package/dist/mcp/tools/precision-warp.js.map +1 -1
  204. package/dist/mcp/tools/refactor-difficulty.d.ts +3 -0
  205. package/dist/mcp/tools/refactor-difficulty.d.ts.map +1 -0
  206. package/dist/mcp/tools/refactor-difficulty.js +36 -0
  207. package/dist/mcp/tools/refactor-difficulty.js.map +1 -0
  208. package/dist/mcp/tools/safe-read.js +2 -2
  209. package/dist/mcp/tools/safe-read.js.map +1 -1
  210. package/dist/mcp/tools/structural-blame.d.ts +3 -0
  211. package/dist/mcp/tools/structural-blame.d.ts.map +1 -0
  212. package/dist/mcp/tools/structural-blame.js +44 -0
  213. package/dist/mcp/tools/structural-blame.js.map +1 -0
  214. package/dist/mcp/tools/structural-churn.d.ts +3 -0
  215. package/dist/mcp/tools/structural-churn.d.ts.map +1 -0
  216. package/dist/mcp/tools/structural-churn.js +28 -0
  217. package/dist/mcp/tools/structural-churn.js.map +1 -0
  218. package/dist/mcp/tools/structural-log.d.ts +3 -0
  219. package/dist/mcp/tools/structural-log.d.ts.map +1 -0
  220. package/dist/mcp/tools/structural-log.js +38 -0
  221. package/dist/mcp/tools/structural-log.js.map +1 -0
  222. package/dist/mcp/tools/structural-review.d.ts +3 -0
  223. package/dist/mcp/tools/structural-review.d.ts.map +1 -0
  224. package/dist/mcp/tools/structural-review.js +55 -0
  225. package/dist/mcp/tools/structural-review.js.map +1 -0
  226. package/dist/mcp/warp-pool.d.ts +4 -4
  227. package/dist/mcp/warp-pool.d.ts.map +1 -1
  228. package/dist/mcp/warp-pool.js.map +1 -1
  229. package/dist/mcp/workspace-router-model.d.ts +2 -2
  230. package/dist/mcp/workspace-router-model.d.ts.map +1 -1
  231. package/dist/mcp/workspace-router-runtime.d.ts +3 -3
  232. package/dist/mcp/workspace-router-runtime.d.ts.map +1 -1
  233. package/dist/mcp/workspace-router-runtime.js +4 -1
  234. package/dist/mcp/workspace-router-runtime.js.map +1 -1
  235. package/dist/mcp/workspace-router.d.ts +3 -2
  236. package/dist/mcp/workspace-router.d.ts.map +1 -1
  237. package/dist/mcp/workspace-router.js +6 -0
  238. package/dist/mcp/workspace-router.js.map +1 -1
  239. package/dist/operations/adaptive-projection.d.ts +22 -0
  240. package/dist/operations/adaptive-projection.d.ts.map +1 -0
  241. package/dist/operations/adaptive-projection.js +36 -0
  242. package/dist/operations/adaptive-projection.js.map +1 -0
  243. package/dist/operations/agent-handoff.d.ts +25 -0
  244. package/dist/operations/agent-handoff.d.ts.map +1 -0
  245. package/dist/operations/agent-handoff.js +36 -0
  246. package/dist/operations/agent-handoff.js.map +1 -0
  247. package/dist/operations/capture-range.d.ts +33 -0
  248. package/dist/operations/capture-range.d.ts.map +1 -0
  249. package/dist/operations/capture-range.js +45 -0
  250. package/dist/operations/capture-range.js.map +1 -0
  251. package/dist/operations/conversation-primer.d.ts +27 -0
  252. package/dist/operations/conversation-primer.d.ts.map +1 -0
  253. package/dist/operations/conversation-primer.js +52 -0
  254. package/dist/operations/conversation-primer.js.map +1 -0
  255. package/dist/operations/cross-session-resume.d.ts +28 -0
  256. package/dist/operations/cross-session-resume.d.ts.map +1 -0
  257. package/dist/operations/cross-session-resume.js +79 -0
  258. package/dist/operations/cross-session-resume.js.map +1 -0
  259. package/dist/operations/deterministic-replay.d.ts +39 -0
  260. package/dist/operations/deterministic-replay.d.ts.map +1 -0
  261. package/dist/operations/deterministic-replay.js +90 -0
  262. package/dist/operations/deterministic-replay.js.map +1 -0
  263. package/dist/operations/export-surface-diff.d.ts +36 -0
  264. package/dist/operations/export-surface-diff.d.ts.map +1 -0
  265. package/dist/operations/export-surface-diff.js +298 -0
  266. package/dist/operations/export-surface-diff.js.map +1 -0
  267. package/dist/operations/footprint-parallelism.d.ts +25 -0
  268. package/dist/operations/footprint-parallelism.d.ts.map +1 -0
  269. package/dist/operations/footprint-parallelism.js +79 -0
  270. package/dist/operations/footprint-parallelism.js.map +1 -0
  271. package/dist/operations/graft-diff.d.ts.map +1 -1
  272. package/dist/operations/graft-diff.js +14 -7
  273. package/dist/operations/graft-diff.js.map +1 -1
  274. package/dist/operations/horizon-of-readability.d.ts +23 -0
  275. package/dist/operations/horizon-of-readability.d.ts.map +1 -0
  276. package/dist/operations/horizon-of-readability.js +39 -0
  277. package/dist/operations/horizon-of-readability.js.map +1 -0
  278. package/dist/operations/import-reference-impact.d.ts +13 -0
  279. package/dist/operations/import-reference-impact.d.ts.map +1 -0
  280. package/dist/operations/import-reference-impact.js +101 -0
  281. package/dist/operations/import-reference-impact.js.map +1 -0
  282. package/dist/operations/knowledge-map.d.ts +30 -0
  283. package/dist/operations/knowledge-map.d.ts.map +1 -0
  284. package/dist/operations/knowledge-map.js +64 -0
  285. package/dist/operations/knowledge-map.js.map +1 -0
  286. package/dist/operations/observation-cache.d.ts +8 -2
  287. package/dist/operations/observation-cache.d.ts.map +1 -1
  288. package/dist/operations/observation-cache.js +17 -5
  289. package/dist/operations/observation-cache.js.map +1 -1
  290. package/dist/operations/projection-safety.d.ts +31 -0
  291. package/dist/operations/projection-safety.d.ts.map +1 -0
  292. package/dist/operations/projection-safety.js +77 -0
  293. package/dist/operations/projection-safety.js.map +1 -0
  294. package/dist/operations/repo-workspace.js +3 -3
  295. package/dist/operations/repo-workspace.js.map +1 -1
  296. package/dist/operations/semantic-drift.d.ts +27 -0
  297. package/dist/operations/semantic-drift.d.ts.map +1 -0
  298. package/dist/operations/semantic-drift.js +46 -0
  299. package/dist/operations/semantic-drift.js.map +1 -0
  300. package/dist/operations/session-filtration.d.ts +36 -0
  301. package/dist/operations/session-filtration.d.ts.map +1 -0
  302. package/dist/operations/session-filtration.js +48 -0
  303. package/dist/operations/session-filtration.js.map +1 -0
  304. package/dist/operations/session-replay.d.ts +17 -0
  305. package/dist/operations/session-replay.d.ts.map +1 -0
  306. package/dist/operations/session-replay.js +59 -0
  307. package/dist/operations/session-replay.js.map +1 -0
  308. package/dist/operations/sludge-detector.d.ts +45 -0
  309. package/dist/operations/sludge-detector.d.ts.map +1 -0
  310. package/dist/operations/sludge-detector.js +278 -0
  311. package/dist/operations/sludge-detector.js.map +1 -0
  312. package/dist/operations/structural-blame.d.ts +67 -0
  313. package/dist/operations/structural-blame.d.ts.map +1 -0
  314. package/dist/operations/structural-blame.js +111 -0
  315. package/dist/operations/structural-blame.js.map +1 -0
  316. package/dist/operations/structural-review.d.ts +47 -0
  317. package/dist/operations/structural-review.d.ts.map +1 -0
  318. package/dist/operations/structural-review.js +225 -0
  319. package/dist/operations/structural-review.js.map +1 -0
  320. package/dist/operations/teaching-hints.d.ts +18 -0
  321. package/dist/operations/teaching-hints.d.ts.map +1 -0
  322. package/dist/operations/teaching-hints.js +35 -0
  323. package/dist/operations/teaching-hints.js.map +1 -0
  324. package/dist/parser/diff.d.ts +2 -0
  325. package/dist/parser/diff.d.ts.map +1 -1
  326. package/dist/parser/diff.js +7 -0
  327. package/dist/parser/diff.js.map +1 -1
  328. package/dist/ports/paths.d.ts +17 -0
  329. package/dist/ports/paths.d.ts.map +1 -0
  330. package/dist/ports/{warp.js → paths.js} +2 -2
  331. package/dist/ports/paths.js.map +1 -0
  332. package/dist/warp/ast-emitter.d.ts +28 -0
  333. package/dist/warp/ast-emitter.d.ts.map +1 -0
  334. package/dist/warp/ast-emitter.js +90 -0
  335. package/dist/warp/ast-emitter.js.map +1 -0
  336. package/dist/warp/ast-import-resolver.d.ts +13 -0
  337. package/dist/warp/ast-import-resolver.d.ts.map +1 -0
  338. package/dist/warp/ast-import-resolver.js +259 -0
  339. package/dist/warp/ast-import-resolver.js.map +1 -0
  340. package/dist/warp/commit-meta.d.ts +8 -0
  341. package/dist/warp/commit-meta.d.ts.map +1 -0
  342. package/dist/warp/commit-meta.js +13 -0
  343. package/dist/warp/commit-meta.js.map +1 -0
  344. package/dist/warp/context.d.ts +10 -0
  345. package/dist/warp/context.d.ts.map +1 -0
  346. package/dist/warp/context.js +26 -0
  347. package/dist/warp/context.js.map +1 -0
  348. package/dist/warp/dead-symbols.d.ts +40 -0
  349. package/dist/warp/dead-symbols.d.ts.map +1 -0
  350. package/dist/warp/dead-symbols.js +127 -0
  351. package/dist/warp/dead-symbols.js.map +1 -0
  352. package/dist/warp/drift-sentinel.d.ts +30 -0
  353. package/dist/warp/drift-sentinel.d.ts.map +1 -0
  354. package/dist/warp/drift-sentinel.js +65 -0
  355. package/dist/warp/drift-sentinel.js.map +1 -0
  356. package/dist/warp/index-head.d.ts +32 -0
  357. package/dist/warp/index-head.d.ts.map +1 -0
  358. package/dist/warp/index-head.js +245 -0
  359. package/dist/warp/index-head.js.map +1 -0
  360. package/dist/warp/observers.d.ts +6 -6
  361. package/dist/warp/observers.d.ts.map +1 -1
  362. package/dist/warp/observers.js +5 -4
  363. package/dist/warp/observers.js.map +1 -1
  364. package/dist/warp/open.d.ts +5 -4
  365. package/dist/warp/open.d.ts.map +1 -1
  366. package/dist/warp/open.js +24 -49
  367. package/dist/warp/open.js.map +1 -1
  368. package/dist/warp/outline-diff-trailer.d.ts +26 -0
  369. package/dist/warp/outline-diff-trailer.d.ts.map +1 -0
  370. package/dist/warp/outline-diff-trailer.js +68 -0
  371. package/dist/warp/outline-diff-trailer.js.map +1 -0
  372. package/dist/warp/refactor-difficulty.d.ts +38 -0
  373. package/dist/warp/refactor-difficulty.d.ts.map +1 -0
  374. package/dist/warp/refactor-difficulty.js +169 -0
  375. package/dist/warp/refactor-difficulty.js.map +1 -0
  376. package/dist/warp/references.d.ts +22 -0
  377. package/dist/warp/references.d.ts.map +1 -0
  378. package/dist/warp/references.js +57 -0
  379. package/dist/warp/references.js.map +1 -0
  380. package/dist/warp/stale-docs.d.ts +56 -0
  381. package/dist/warp/stale-docs.d.ts.map +1 -0
  382. package/dist/warp/stale-docs.js +149 -0
  383. package/dist/warp/stale-docs.js.map +1 -0
  384. package/dist/warp/structural-drift-detection.d.ts +49 -0
  385. package/dist/warp/structural-drift-detection.d.ts.map +1 -0
  386. package/dist/warp/structural-drift-detection.js +51 -0
  387. package/dist/warp/structural-drift-detection.js.map +1 -0
  388. package/dist/warp/structural-queries.d.ts +49 -0
  389. package/dist/warp/structural-queries.d.ts.map +1 -0
  390. package/dist/warp/structural-queries.js +175 -0
  391. package/dist/warp/structural-queries.js.map +1 -0
  392. package/dist/warp/symbol-timeline.d.ts +34 -0
  393. package/dist/warp/symbol-timeline.d.ts.map +1 -0
  394. package/dist/warp/symbol-timeline.js +127 -0
  395. package/dist/warp/symbol-timeline.js.map +1 -0
  396. package/dist/warp/traverse-hydrate.d.ts +23 -0
  397. package/dist/warp/traverse-hydrate.d.ts.map +1 -0
  398. package/dist/warp/traverse-hydrate.js +39 -0
  399. package/dist/warp/traverse-hydrate.js.map +1 -0
  400. package/dist/warp/warp-reference-count.d.ts +19 -0
  401. package/dist/warp/warp-reference-count.d.ts.map +1 -0
  402. package/dist/warp/warp-reference-count.js +32 -0
  403. package/dist/warp/warp-reference-count.js.map +1 -0
  404. package/dist/warp/warp-structural-blame.d.ts +20 -0
  405. package/dist/warp/warp-structural-blame.d.ts.map +1 -0
  406. package/dist/warp/warp-structural-blame.js +43 -0
  407. package/dist/warp/warp-structural-blame.js.map +1 -0
  408. package/dist/warp/warp-structural-churn.d.ts +30 -0
  409. package/dist/warp/warp-structural-churn.d.ts.map +1 -0
  410. package/dist/warp/warp-structural-churn.js +213 -0
  411. package/dist/warp/warp-structural-churn.js.map +1 -0
  412. package/dist/warp/warp-structural-log.d.ts +35 -0
  413. package/dist/warp/warp-structural-log.d.ts.map +1 -0
  414. package/dist/warp/warp-structural-log.js +104 -0
  415. package/dist/warp/warp-structural-log.js.map +1 -0
  416. package/docs/CLI.md +68 -4
  417. package/docs/MCP.md +23 -0
  418. package/docs/SETUP.md +779 -0
  419. package/package.json +10 -7
  420. package/src/adapters/json-text-decoder.ts +11 -0
  421. package/src/adapters/node-paths.ts +35 -0
  422. package/src/adapters/repo-paths.ts +45 -4
  423. package/src/api/tool-bridge.ts +2 -1
  424. package/src/cli/cli-error.ts +49 -10
  425. package/src/cli/command-parser.ts +185 -3
  426. package/src/cli/daemon-status-model.ts +238 -0
  427. package/src/cli/daemon-status-render.ts +102 -0
  428. package/src/cli/daemon-status.ts +100 -0
  429. package/src/cli/git-graft-enhance-model.ts +131 -0
  430. package/src/cli/git-graft-enhance-render.ts +33 -0
  431. package/src/cli/git-graft-enhance.ts +54 -0
  432. package/src/cli/index-cmd.ts +18 -22
  433. package/src/cli/index-model.ts +21 -22
  434. package/src/cli/init-client-config.ts +167 -38
  435. package/src/cli/init-model.ts +57 -2
  436. package/src/cli/init-render.ts +2 -2
  437. package/src/cli/init.ts +11 -9
  438. package/src/cli/json-document.ts +11 -0
  439. package/src/cli/main.ts +53 -6
  440. package/src/cli/migrate-local-history.ts +3 -2
  441. package/src/cli/peer-command.ts +2 -1
  442. package/src/contracts/capabilities.ts +90 -0
  443. package/src/contracts/json-object.ts +1 -11
  444. package/src/contracts/output-schema-cli.ts +36 -3
  445. package/src/contracts/output-schema-fragments.ts +52 -2
  446. package/src/contracts/output-schema-mcp.ts +219 -0
  447. package/src/contracts/output-schemas.ts +300 -6
  448. package/src/git/diff.ts +61 -0
  449. package/src/mcp/burden.ts +9 -0
  450. package/src/mcp/context.ts +5 -42
  451. package/src/mcp/daemon-server.ts +8 -1
  452. package/src/mcp/daemon-session-host.ts +4 -0
  453. package/src/mcp/daemon-stdio-bridge.ts +2 -0
  454. package/src/mcp/monitor-tick-job.ts +90 -39
  455. package/src/mcp/monitor-types.ts +1 -1
  456. package/src/mcp/persisted-local-history-graph.ts +5 -4
  457. package/src/mcp/persisted-local-history.ts +2 -2
  458. package/src/mcp/persistent-monitor-runtime.ts +37 -0
  459. package/src/mcp/repo-tool-worker-context.ts +5 -2
  460. package/src/mcp/server-context.ts +15 -2
  461. package/src/mcp/server-tool-access.ts +4 -1
  462. package/src/mcp/server.ts +8 -3
  463. package/src/mcp/tool-registry.ts +18 -0
  464. package/src/mcp/tools/code-find.ts +23 -0
  465. package/src/mcp/tools/code-show.ts +27 -0
  466. package/src/mcp/tools/diagnostic-models.ts +2 -0
  467. package/src/mcp/tools/doctor.ts +18 -1
  468. package/src/mcp/tools/export-surface-diff.ts +26 -0
  469. package/src/mcp/tools/file-outline.ts +1 -1
  470. package/src/mcp/tools/graft-edit.ts +276 -0
  471. package/src/mcp/tools/knowledge-map.ts +34 -0
  472. package/src/mcp/tools/monitor-nudge.ts +19 -0
  473. package/src/mcp/tools/precision-warp.ts +27 -16
  474. package/src/mcp/tools/refactor-difficulty.ts +42 -0
  475. package/src/mcp/tools/safe-read.ts +2 -2
  476. package/src/mcp/tools/structural-blame.ts +55 -0
  477. package/src/mcp/tools/structural-churn.ts +28 -0
  478. package/src/mcp/tools/structural-log.ts +41 -0
  479. package/src/mcp/tools/structural-review.ts +63 -0
  480. package/src/mcp/warp-pool.ts +6 -6
  481. package/src/mcp/workspace-router-model.ts +2 -2
  482. package/src/mcp/workspace-router-runtime.ts +11 -8
  483. package/src/mcp/workspace-router.ts +9 -2
  484. package/src/operations/adaptive-projection.ts +54 -0
  485. package/src/operations/agent-handoff.ts +59 -0
  486. package/src/operations/capture-range.ts +64 -0
  487. package/src/operations/conversation-primer.ts +82 -0
  488. package/src/operations/cross-session-resume.ts +104 -0
  489. package/src/operations/deterministic-replay.ts +143 -0
  490. package/src/operations/export-surface-diff.ts +355 -0
  491. package/src/operations/footprint-parallelism.ts +98 -0
  492. package/src/operations/graft-diff.ts +14 -7
  493. package/src/operations/horizon-of-readability.ts +60 -0
  494. package/src/operations/import-reference-impact.ts +143 -0
  495. package/src/operations/knowledge-map.ts +96 -0
  496. package/src/operations/observation-cache.ts +20 -4
  497. package/src/operations/projection-safety.ts +111 -0
  498. package/src/operations/repo-workspace.ts +3 -3
  499. package/src/operations/semantic-drift.ts +70 -0
  500. package/src/operations/session-filtration.ts +76 -0
  501. package/src/operations/session-replay.ts +73 -0
  502. package/src/operations/sludge-detector.ts +356 -0
  503. package/src/operations/structural-blame.ts +197 -0
  504. package/src/operations/structural-review.ts +317 -0
  505. package/src/operations/teaching-hints.ts +52 -0
  506. package/src/parser/diff.ts +7 -0
  507. package/src/ports/paths.ts +22 -0
  508. package/src/warp/ast-emitter.ts +133 -0
  509. package/src/warp/ast-import-resolver.ts +333 -0
  510. package/src/warp/commit-meta.ts +19 -0
  511. package/src/warp/context.ts +48 -0
  512. package/src/warp/dead-symbols.ts +174 -0
  513. package/src/warp/drift-sentinel.ts +101 -0
  514. package/src/warp/index-head.ts +348 -0
  515. package/src/warp/observers.ts +8 -7
  516. package/src/warp/open.ts +40 -66
  517. package/src/warp/outline-diff-trailer.ts +100 -0
  518. package/src/warp/plumbing.d.ts +11 -2
  519. package/src/warp/refactor-difficulty.ts +257 -0
  520. package/src/warp/references.ts +77 -0
  521. package/src/warp/stale-docs.ts +210 -0
  522. package/src/warp/structural-drift-detection.ts +97 -0
  523. package/src/warp/structural-queries.ts +258 -0
  524. package/src/warp/symbol-timeline.ts +209 -0
  525. package/src/warp/traverse-hydrate.ts +61 -0
  526. package/src/warp/warp-reference-count.ts +47 -0
  527. package/src/warp/warp-structural-blame.ts +65 -0
  528. package/src/warp/warp-structural-churn.ts +309 -0
  529. package/src/warp/warp-structural-log.ts +149 -0
  530. package/dist/ports/warp.d.ts +0 -45
  531. package/dist/ports/warp.d.ts.map +0 -1
  532. package/dist/ports/warp.js.map +0 -1
  533. package/dist/warp/identity-resolver.d.ts +0 -14
  534. package/dist/warp/identity-resolver.d.ts.map +0 -1
  535. package/dist/warp/identity-resolver.js +0 -31
  536. package/dist/warp/identity-resolver.js.map +0 -1
  537. package/dist/warp/indexer-git.d.ts +0 -22
  538. package/dist/warp/indexer-git.d.ts.map +0 -1
  539. package/dist/warp/indexer-git.js +0 -148
  540. package/dist/warp/indexer-git.js.map +0 -1
  541. package/dist/warp/indexer-graph.d.ts +0 -17
  542. package/dist/warp/indexer-graph.d.ts.map +0 -1
  543. package/dist/warp/indexer-graph.js +0 -179
  544. package/dist/warp/indexer-graph.js.map +0 -1
  545. package/dist/warp/indexer-model.d.ts +0 -51
  546. package/dist/warp/indexer-model.d.ts.map +0 -1
  547. package/dist/warp/indexer-model.js +0 -21
  548. package/dist/warp/indexer-model.js.map +0 -1
  549. package/dist/warp/indexer.d.ts +0 -9
  550. package/dist/warp/indexer.d.ts.map +0 -1
  551. package/dist/warp/indexer.js +0 -112
  552. package/dist/warp/indexer.js.map +0 -1
  553. package/dist/warp/symbol-identity.d.ts +0 -11
  554. package/dist/warp/symbol-identity.d.ts.map +0 -1
  555. package/dist/warp/symbol-identity.js +0 -67
  556. package/dist/warp/symbol-identity.js.map +0 -1
  557. package/src/ports/warp.ts +0 -55
  558. package/src/warp/identity-resolver.ts +0 -35
  559. package/src/warp/indexer-git.ts +0 -182
  560. package/src/warp/indexer-graph.ts +0 -276
  561. package/src/warp/indexer-model.ts +0 -69
  562. package/src/warp/indexer.ts +0 -186
  563. package/src/warp/symbol-identity.ts +0 -100
@@ -0,0 +1,317 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Structural Review — zero-noise PR review separating signal from formatting
3
+ // ---------------------------------------------------------------------------
4
+
5
+ import type { FileSystem } from "../ports/filesystem.js";
6
+ import type { GitClient } from "../ports/git.js";
7
+ import { graftDiff, type FileDiff, type GraftDiffOptions } from "./graft-diff.js";
8
+ import { getChangedFilesWithStatus } from "../git/diff.js";
9
+
10
+ // ---- Public types ---------------------------------------------------------
11
+
12
+ export interface ReferenceCountResult {
13
+ readonly referenceCount: number;
14
+ readonly referencingFiles: readonly string[];
15
+ }
16
+
17
+ export type ReferenceCounter = (
18
+ symbolName: string,
19
+ filePath: string,
20
+ ) => Promise<ReferenceCountResult>;
21
+
22
+
23
+ export type ReviewCategory = "structural" | "formatting" | "test" | "docs" | "config";
24
+
25
+ export interface ReviewFile {
26
+ readonly path: string;
27
+ readonly category: ReviewCategory;
28
+ readonly structuralChanges?: { added: number; removed: number; changed: number };
29
+ }
30
+
31
+ export interface BreakingChange {
32
+ readonly symbol: string;
33
+ readonly kind: string;
34
+ readonly filePath: string;
35
+ readonly changeType: "removed_export" | "signature_changed" | "type_changed";
36
+ readonly previousSignature?: string;
37
+ readonly newSignature?: string;
38
+ readonly impactedFiles: number;
39
+ readonly impactedFilePaths: readonly string[];
40
+ }
41
+
42
+ export interface StructuralReviewResult {
43
+ readonly base: string;
44
+ readonly head: string;
45
+ readonly totalFiles: number;
46
+ readonly categories: Record<ReviewCategory, number>;
47
+ readonly files: readonly ReviewFile[];
48
+ readonly breakingChanges: readonly BreakingChange[];
49
+ readonly summary: string;
50
+ }
51
+
52
+ export interface StructuralReviewOptions {
53
+ readonly cwd: string;
54
+ readonly fs: FileSystem;
55
+ readonly git: GitClient;
56
+ readonly resolveWorkingTreePath: (filePath: string) => string;
57
+ readonly base?: string | undefined;
58
+ readonly head?: string | undefined;
59
+ readonly countReferences: ReferenceCounter;
60
+ }
61
+
62
+ // ---- File categorization --------------------------------------------------
63
+
64
+ const CONFIG_PATTERNS = [
65
+ "package.json",
66
+ "tsconfig",
67
+ "eslint",
68
+ ".prettierrc",
69
+ ".editorconfig",
70
+ "vitest.config",
71
+ "jest.config",
72
+ "rollup.config",
73
+ "vite.config",
74
+ "webpack.config",
75
+ "babel.config",
76
+ ".babelrc",
77
+ ".npmrc",
78
+ ".nvmrc",
79
+ ".gitignore",
80
+ ".gitattributes",
81
+ "pnpm-lock.yaml",
82
+ "pnpm-workspace.yaml",
83
+ "yarn.lock",
84
+ "package-lock.json",
85
+ "Makefile",
86
+ "Dockerfile",
87
+ "docker-compose",
88
+ ];
89
+
90
+ const TEST_PATTERNS = [
91
+ "/test/",
92
+ "/tests/",
93
+ "/__tests__/",
94
+ ".test.",
95
+ ".spec.",
96
+ "_test.",
97
+ ];
98
+
99
+ function isTestFile(filePath: string): boolean {
100
+ return TEST_PATTERNS.some((p) => filePath.includes(p));
101
+ }
102
+
103
+ function isDocsFile(filePath: string): boolean {
104
+ return filePath.endsWith(".md") || filePath.endsWith(".txt") || filePath.endsWith(".rst");
105
+ }
106
+
107
+ function isConfigFile(filePath: string): boolean {
108
+ const lower = filePath.toLowerCase();
109
+ return CONFIG_PATTERNS.some((p) => lower.includes(p));
110
+ }
111
+
112
+ // ---- Breaking change detection --------------------------------------------
113
+
114
+ async function detectBreakingChanges(
115
+ structuralFiles: readonly FileDiff[],
116
+ countReferences: ReferenceCounter,
117
+ ): Promise<BreakingChange[]> {
118
+ const breaking: BreakingChange[] = [];
119
+
120
+ for (const file of structuralFiles) {
121
+ // Removed exports → breaking
122
+ for (const removed of file.diff.removed) {
123
+ if (removed.exported !== true) continue;
124
+ const refs = await countReferences(removed.name, file.path);
125
+ breaking.push({
126
+ symbol: removed.name,
127
+ kind: removed.kind,
128
+ filePath: file.path,
129
+ changeType: "removed_export",
130
+ ...(removed.signature !== undefined ? { previousSignature: removed.signature } : {}),
131
+ impactedFiles: refs.referenceCount,
132
+ impactedFilePaths: refs.referencingFiles,
133
+ });
134
+ }
135
+
136
+ // Changed exported symbol signatures → potentially breaking
137
+ for (const changed of file.diff.changed) {
138
+ if (changed.exported !== true) continue;
139
+ if (changed.oldSignature !== undefined && changed.signature !== undefined &&
140
+ changed.oldSignature !== changed.signature) {
141
+ const refs = await countReferences(changed.name, file.path);
142
+ breaking.push({
143
+ symbol: changed.name,
144
+ kind: changed.kind,
145
+ filePath: file.path,
146
+ changeType: "signature_changed",
147
+ previousSignature: changed.oldSignature,
148
+ newSignature: changed.signature,
149
+ impactedFiles: refs.referenceCount,
150
+ impactedFilePaths: refs.referencingFiles,
151
+ });
152
+ }
153
+ }
154
+ }
155
+
156
+ return breaking;
157
+ }
158
+
159
+ // ---- Summary rendering ----------------------------------------------------
160
+
161
+ function renderSummary(
162
+ base: string,
163
+ head: string,
164
+ categories: Record<ReviewCategory, number>,
165
+ breakingChanges: readonly BreakingChange[],
166
+ totalFiles: number,
167
+ structuralFiles: readonly FileDiff[],
168
+ ): string {
169
+ const parts: string[] = [];
170
+ parts.push(`PR Review: ${base}..${head} — ${String(totalFiles)} files changed`);
171
+ parts.push("");
172
+
173
+ // Structural details
174
+ if (categories.structural > 0) {
175
+ const totalAdded = structuralFiles.reduce((n, f) => n + f.diff.added.length, 0);
176
+ const totalChanged = structuralFiles.reduce((n, f) => n + f.diff.changed.length, 0);
177
+ const totalRemoved = structuralFiles.reduce((n, f) => n + f.diff.removed.length, 0);
178
+ const details: string[] = [];
179
+ if (totalAdded > 0) details.push(`${String(totalAdded)} new exports`);
180
+ if (totalChanged > 0) details.push(`${String(totalChanged)} sig changes`);
181
+ if (totalRemoved > 0) details.push(`${String(totalRemoved)} removed`);
182
+ const suffix = details.length > 0 ? ` (${details.join(", ")})` : "";
183
+ parts.push(` Structural: ${String(categories.structural)} files${suffix}`);
184
+ }
185
+ if (categories.formatting > 0) {
186
+ parts.push(` Formatting: ${String(categories.formatting)} files`);
187
+ }
188
+ if (categories.test > 0) {
189
+ parts.push(` Tests: ${String(categories.test)} files`);
190
+ }
191
+ if (categories.docs > 0) {
192
+ parts.push(` Docs: ${String(categories.docs)} files`);
193
+ }
194
+ if (categories.config > 0) {
195
+ parts.push(` Config: ${String(categories.config)} files`);
196
+ }
197
+
198
+ // Breaking changes
199
+ for (const bc of breakingChanges) {
200
+ parts.push("");
201
+ if (bc.changeType === "removed_export") {
202
+ parts.push(` ⚠ BREAKING: ${bc.symbol} — removed export`);
203
+ if (bc.previousSignature !== undefined) {
204
+ parts.push(` Was: ${bc.previousSignature}`);
205
+ }
206
+ } else {
207
+ parts.push(` ⚠ BREAKING: ${bc.symbol} — signature changed`);
208
+ if (bc.previousSignature !== undefined) {
209
+ parts.push(` Was: ${bc.previousSignature}`);
210
+ }
211
+ if (bc.newSignature !== undefined) {
212
+ parts.push(` Now: ${bc.newSignature}`);
213
+ }
214
+ }
215
+ parts.push(` Impact: referenced by ${String(bc.impactedFiles)} files`);
216
+ }
217
+
218
+ return parts.join("\n");
219
+ }
220
+
221
+ // ---- Public API -----------------------------------------------------------
222
+
223
+ export async function structuralReview(
224
+ opts: StructuralReviewOptions,
225
+ ): Promise<StructuralReviewResult> {
226
+ const base = opts.base ?? "main";
227
+ const head = opts.head ?? "HEAD";
228
+
229
+ // 1. Get structural diff
230
+ const diffOpts: GraftDiffOptions = {
231
+ cwd: opts.cwd,
232
+ fs: opts.fs,
233
+ git: opts.git,
234
+ resolveWorkingTreePath: opts.resolveWorkingTreePath,
235
+ base,
236
+ head,
237
+ };
238
+ const structDiff = await graftDiff(diffOpts);
239
+
240
+ // 2. Get ALL changed files with rename detection
241
+ const allChangedEntries = await getChangedFilesWithStatus({
242
+ cwd: opts.cwd,
243
+ git: opts.git,
244
+ base,
245
+ head,
246
+ });
247
+ const allChangedPaths = allChangedEntries.map((e) => e.path);
248
+
249
+ // 3. Build set of structurally-changed file paths
250
+ const structuralPaths = new Set(structDiff.files.map((f) => f.path));
251
+
252
+ // 4. Categorize each changed file
253
+ const files: ReviewFile[] = [];
254
+ for (const filePath of allChangedPaths) {
255
+ // Check if the file has actual structural (symbol-level) changes
256
+ const fileDiff = structuralPaths.has(filePath)
257
+ ? structDiff.files.find((f) => f.path === filePath)
258
+ : undefined;
259
+ const diff = fileDiff?.diff;
260
+ const hasStructuralChanges = diff !== undefined &&
261
+ (diff.added.length > 0 || diff.removed.length > 0 || diff.changed.length > 0);
262
+
263
+ if (hasStructuralChanges) {
264
+ files.push({
265
+ path: filePath,
266
+ category: "structural",
267
+ structuralChanges: { added: diff.added.length, removed: diff.removed.length, changed: diff.changed.length },
268
+ });
269
+ } else if (isTestFile(filePath)) {
270
+ files.push({ path: filePath, category: "test" });
271
+ } else if (isDocsFile(filePath)) {
272
+ files.push({ path: filePath, category: "docs" });
273
+ } else if (isConfigFile(filePath)) {
274
+ files.push({ path: filePath, category: "config" });
275
+ } else {
276
+ files.push({ path: filePath, category: "formatting" });
277
+ }
278
+ }
279
+
280
+ // 5. Count categories
281
+ const categories: Record<ReviewCategory, number> = {
282
+ structural: 0,
283
+ formatting: 0,
284
+ test: 0,
285
+ docs: 0,
286
+ config: 0,
287
+ };
288
+ for (const file of files) {
289
+ categories[file.category]++;
290
+ }
291
+
292
+ // 6. Detect breaking changes in structural files
293
+ const structuralFileDiffs = structDiff.files.filter((f) =>
294
+ f.diff.removed.length > 0 || f.diff.changed.length > 0,
295
+ );
296
+ const breakingChanges = await detectBreakingChanges(structuralFileDiffs, opts.countReferences);
297
+
298
+ // 7. Render summary
299
+ const summary = renderSummary(
300
+ base,
301
+ head,
302
+ categories,
303
+ breakingChanges,
304
+ allChangedPaths.length,
305
+ structDiff.files,
306
+ );
307
+
308
+ return {
309
+ base,
310
+ head,
311
+ totalFiles: allChangedPaths.length,
312
+ categories,
313
+ files,
314
+ breakingChanges,
315
+ summary,
316
+ };
317
+ }
@@ -0,0 +1,52 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Teaching Hints — contextual guidance for suboptimal read decisions
3
+ // ---------------------------------------------------------------------------
4
+
5
+ /** Context about a projection decision for hint generation. */
6
+ export interface ProjectionContext {
7
+ readonly projection: "content" | "outline" | "refused";
8
+ readonly reason: string;
9
+ readonly filePath: string;
10
+ readonly fileLines: number;
11
+ readonly fileBytes: number;
12
+ readonly readCount: number;
13
+ readonly changedSinceLastRead?: boolean;
14
+ }
15
+
16
+ const LARGE_FILE_THRESHOLD = 150;
17
+ const BUILD_OUTPUT_DIRS = ["dist/", "build/", "out/", ".next/", "coverage/"];
18
+
19
+ /**
20
+ * Generate a teaching hint for a projection decision.
21
+ *
22
+ * Returns undefined when the decision was already optimal (no noise).
23
+ * Pure function — no I/O, no latency impact.
24
+ */
25
+ export function generateTeachingHint(ctx: ProjectionContext): string | undefined {
26
+ // Refused — suggest the source location
27
+ if (ctx.projection === "refused") {
28
+ if (BUILD_OUTPUT_DIRS.some((dir) => ctx.filePath.startsWith(dir))) {
29
+ return `This build output was refused. Source lives in src/, not ${ctx.filePath.split("/")[0] ?? "dist"}/. Read the source instead.`;
30
+ }
31
+ return `This file was refused (${ctx.reason}). Check if the content you need lives elsewhere.`;
32
+ }
33
+
34
+ // Outline-projected — suggest file_outline + read_range
35
+ if (ctx.projection === "outline") {
36
+ return `This file was outline-projected (${ctx.reason}). Try file_outline first to see the jump table, then read_range for the specific symbol you need.`;
37
+ }
38
+
39
+
40
+ // Re-read of unchanged file
41
+ if (ctx.readCount > 1 && ctx.changedSinceLastRead === false) {
42
+ return `You already read this file ${String(ctx.readCount)} times and it hasn't changed. Use changed_since to check before re-reading.`;
43
+ }
44
+
45
+ // Large file that could benefit from outline-first
46
+ if (ctx.fileLines > LARGE_FILE_THRESHOLD) {
47
+ return `This file is ${String(ctx.fileLines)} lines. Consider file_outline first for orientation, then read_range for the specific section you need.`;
48
+ }
49
+
50
+ // Optimal decision — no hint needed
51
+ return undefined;
52
+ }
@@ -48,6 +48,7 @@ export class DiffEntry {
48
48
  private readonly _brand = "DiffEntry" as const;
49
49
  readonly name: string;
50
50
  readonly kind: OutlineEntry["kind"];
51
+ readonly exported?: boolean;
51
52
  readonly signature?: string;
52
53
  readonly oldSignature?: string;
53
54
  readonly childDiff?: OutlineDiff;
@@ -57,6 +58,7 @@ export class DiffEntry {
57
58
  constructor(opts: {
58
59
  name: string;
59
60
  kind: OutlineEntry["kind"];
61
+ exported?: boolean;
60
62
  signature?: string;
61
63
  oldSignature?: string;
62
64
  childDiff?: OutlineDiff;
@@ -67,6 +69,7 @@ export class DiffEntry {
67
69
  }
68
70
  this.name = opts.name.trim();
69
71
  this.kind = opts.kind;
72
+ if (opts.exported !== undefined) this.exported = opts.exported;
70
73
  if (opts.signature !== undefined) this.signature = opts.signature;
71
74
  if (opts.oldSignature !== undefined) this.oldSignature = opts.oldSignature;
72
75
  if (opts.childDiff !== undefined) this.childDiff = opts.childDiff;
@@ -255,6 +258,7 @@ export function diffOutlines(
255
258
  added.push(new DiffEntry({
256
259
  name,
257
260
  kind: newEntry.kind,
261
+ exported: newEntry.exported,
258
262
  ...(newEntry.signature !== undefined ? { signature: newEntry.signature } : {}),
259
263
  }));
260
264
  addedEntries.push(newEntry);
@@ -265,6 +269,7 @@ export function diffOutlines(
265
269
  changed.push(new DiffEntry({
266
270
  name,
267
271
  kind: newEntry.kind,
272
+ exported: newEntry.exported,
268
273
  oldSignature: entrySignature(oldEntry),
269
274
  ...(newEntry.signature !== undefined ? { signature: newEntry.signature } : {}),
270
275
  }));
@@ -276,6 +281,7 @@ export function diffOutlines(
276
281
  const childDiff = diffOutlines(oldChildren, newChildren);
277
282
  if (childDiff.added.length > 0 || childDiff.removed.length > 0 || childDiff.changed.length > 0) {
278
283
  changed.push(new DiffEntry({
284
+ exported: newEntry.exported,
279
285
  name,
280
286
  kind: newEntry.kind,
281
287
  childDiff,
@@ -297,6 +303,7 @@ export function diffOutlines(
297
303
  removed.push(new DiffEntry({
298
304
  name,
299
305
  kind: oldEntry.kind,
306
+ exported: oldEntry.exported,
300
307
  ...(oldEntry.signature !== undefined ? { signature: oldEntry.signature } : {}),
301
308
  }));
302
309
  removedEntries.push(oldEntry);
@@ -0,0 +1,22 @@
1
+ // ---------------------------------------------------------------------------
2
+ // PathOps port — hexagonal boundary for path operations
3
+ // ---------------------------------------------------------------------------
4
+
5
+ /**
6
+ * Portable path operations. Core logic imports this port, not node:path.
7
+ * Node adapter implements it; tests can substitute a mock.
8
+ *
9
+ * All methods accept and return forward-slash paths. Normalization
10
+ * (collapsing `//`, resolving `..`, stripping trailing slashes) happens
11
+ * inside the adapter so callers never see raw platform paths.
12
+ */
13
+ export interface PathOps {
14
+ /** Normalize a path: collapse `//`, resolve `..`, strip trailing `/`. */
15
+ normalize(p: string): string;
16
+
17
+ /** True when `filePath` is exactly `directory` or nested inside it. */
18
+ isWithin(filePath: string, directory: string): boolean;
19
+
20
+ /** Join path segments with forward slashes, normalized. */
21
+ join(...segments: string[]): string;
22
+ }
@@ -0,0 +1,133 @@
1
+ // ---------------------------------------------------------------------------
2
+ // AST snapshot attachment — keeps bulky syntax trees out of graph state
3
+ // ---------------------------------------------------------------------------
4
+
5
+ import { createHash } from "node:crypto";
6
+ import { Buffer } from "node:buffer";
7
+ import type { PatchBuilderV2 } from "@git-stunts/git-warp";
8
+ import type { WarpContext } from "./context.js";
9
+ import { patchGraph } from "./context.js";
10
+
11
+ type TSNode = import("web-tree-sitter").SyntaxNode;
12
+
13
+ const AST_SNAPSHOT_MIME = "application/vnd.graft.ast+json";
14
+
15
+ function hashId(input: string): string {
16
+ return createHash("sha1").update(input).digest("hex").slice(0, 12);
17
+ }
18
+
19
+ function astNodeId(filePath: string, node: TSNode): string {
20
+ const hash = hashId(`${filePath}:${node.type}:${String(node.startIndex)}:${String(node.endIndex)}`);
21
+ return `ast:${filePath}:${hash}`;
22
+ }
23
+
24
+ interface AstSnapshotNode {
25
+ readonly type: string;
26
+ readonly named: boolean;
27
+ readonly startRow: number;
28
+ readonly startCol: number;
29
+ readonly endRow: number;
30
+ readonly endCol: number;
31
+ readonly text?: string | undefined;
32
+ readonly children?: readonly AstSnapshotNode[] | undefined;
33
+ }
34
+
35
+ interface AstSnapshot {
36
+ readonly schema: "graft.ast-snapshot.v1";
37
+ readonly filePath: string;
38
+ readonly root: AstSnapshotNode;
39
+ }
40
+
41
+ function astSnapshotNode(node: TSNode): AstSnapshotNode {
42
+ const children: AstSnapshotNode[] = [];
43
+ for (let index = 0; index < node.childCount; index++) {
44
+ const child = node.child(index);
45
+ if (child !== null) children.push(astSnapshotNode(child));
46
+ }
47
+
48
+ return {
49
+ type: node.type,
50
+ named: node.isNamed(),
51
+ startRow: node.startPosition.row,
52
+ startCol: node.startPosition.column,
53
+ endRow: node.endPosition.row,
54
+ endCol: node.endPosition.column,
55
+ ...(children.length === 0 ? { text: node.text } : {}),
56
+ ...(children.length > 0 ? { children } : {}),
57
+ };
58
+ }
59
+
60
+ function astSnapshot(filePath: string, root: TSNode): AstSnapshot {
61
+ return {
62
+ schema: "graft.ast-snapshot.v1",
63
+ filePath,
64
+ root: astSnapshotNode(root),
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Emit a tiny AST root anchor into graph state.
70
+ *
71
+ * The full tree belongs in an attached blob, not materialized WARP graph
72
+ * state. This anchor preserves a stable graph join point for tools that need
73
+ * to know a file has an attached AST snapshot.
74
+ *
75
+ * Call this inside a `warp.patch()` callback to co-locate AST emission
76
+ * with other graph operations in the same atomic commit.
77
+ */
78
+ export function emitAstNodes(
79
+ patch: PatchBuilderV2,
80
+ filePath: string,
81
+ root: TSNode,
82
+ ): void {
83
+ const fileId = `file:${filePath}`;
84
+
85
+ const rootId = astNodeId(filePath, root);
86
+ patch.addNode(rootId);
87
+ patch.setProperty(rootId, "type", root.type);
88
+ patch.setProperty(rootId, "named", root.isNamed());
89
+ patch.setProperty(rootId, "startRow", root.startPosition.row);
90
+ patch.setProperty(rootId, "startCol", root.startPosition.column);
91
+ patch.setProperty(rootId, "endRow", root.endPosition.row);
92
+ patch.setProperty(rootId, "endCol", root.endPosition.column);
93
+ patch.setProperty(rootId, "filePath", filePath);
94
+ patch.setProperty(rootId, "summaryOnly", true);
95
+
96
+ patch.addEdge(fileId, rootId, "contains_ast");
97
+ }
98
+
99
+ /**
100
+ * Attach the complete tree-sitter CST as node content on the file node.
101
+ *
102
+ * The blob remains reachable through the WARP patch commit tree, but the
103
+ * materialized graph only carries the `_content` OID and metadata.
104
+ */
105
+ export async function attachAstSnapshot(
106
+ patch: PatchBuilderV2,
107
+ filePath: string,
108
+ root: TSNode,
109
+ ): Promise<void> {
110
+ const fileId = `file:${filePath}`;
111
+ const content = Buffer.from(JSON.stringify(astSnapshot(filePath, root)), "utf8");
112
+ await patch.attachContent(fileId, content, {
113
+ mime: AST_SNAPSHOT_MIME,
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Standalone convenience: emit the AST root anchor and attach the full AST
119
+ * snapshot as blob content in one patch.
120
+ */
121
+ export async function emitFullAst(
122
+ ctx: WarpContext,
123
+ filePath: string,
124
+ root: TSNode,
125
+ ): Promise<void> {
126
+ await patchGraph(ctx, async (patch) => {
127
+ const fileId = `file:${filePath}`;
128
+ patch.addNode(fileId);
129
+ patch.setProperty(fileId, "path", filePath);
130
+ emitAstNodes(patch, filePath, root);
131
+ await attachAstSnapshot(patch, filePath, root);
132
+ });
133
+ }