@nanonets/graft 0.21.0 → 0.22.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 (348) hide show
  1. package/README.md +549 -315
  2. package/dist/app/review-process.d.ts.map +1 -1
  3. package/dist/app/review-process.js +6 -5
  4. package/dist/app/review-process.js.map +1 -1
  5. package/dist/app/sources.js +2 -2
  6. package/dist/app/sources.js.map +1 -1
  7. package/dist/ask/ask.d.ts +12 -6
  8. package/dist/ask/ask.d.ts.map +1 -1
  9. package/dist/ask/ask.js +28 -38
  10. package/dist/ask/ask.js.map +1 -1
  11. package/dist/bin/graft.d.ts +3 -0
  12. package/dist/bin/graft.d.ts.map +1 -0
  13. package/dist/bin/graft.js +8 -0
  14. package/dist/bin/graft.js.map +1 -0
  15. package/dist/bin/trail.d.ts +3 -0
  16. package/dist/bin/trail.d.ts.map +1 -0
  17. package/dist/bin/trail.js +6 -0
  18. package/dist/bin/trail.js.map +1 -0
  19. package/dist/blast/blast-cli.d.ts.map +1 -1
  20. package/dist/blast/blast-cli.js +2 -1
  21. package/dist/blast/blast-cli.js.map +1 -1
  22. package/dist/blast/render.d.ts.map +1 -1
  23. package/dist/blast/render.js +3 -2
  24. package/dist/blast/render.js.map +1 -1
  25. package/dist/brand.d.ts +97 -0
  26. package/dist/brand.d.ts.map +1 -0
  27. package/dist/brand.js +254 -0
  28. package/dist/brand.js.map +1 -0
  29. package/dist/check/local-check.d.ts +104 -0
  30. package/dist/check/local-check.d.ts.map +1 -0
  31. package/dist/check/local-check.js +830 -0
  32. package/dist/check/local-check.js.map +1 -0
  33. package/dist/check/types.d.ts +31 -0
  34. package/dist/check/types.d.ts.map +1 -0
  35. package/dist/check/types.js +2 -0
  36. package/dist/check/types.js.map +1 -0
  37. package/dist/claude/format.d.ts +44 -1
  38. package/dist/claude/format.d.ts.map +1 -1
  39. package/dist/claude/format.js +113 -19
  40. package/dist/claude/format.js.map +1 -1
  41. package/dist/claude/hook-layers.d.ts +8 -0
  42. package/dist/claude/hook-layers.d.ts.map +1 -0
  43. package/dist/claude/hook-layers.js +72 -0
  44. package/dist/claude/hook-layers.js.map +1 -0
  45. package/dist/claude/hooks.d.ts +34 -0
  46. package/dist/claude/hooks.d.ts.map +1 -1
  47. package/dist/claude/hooks.js +220 -12
  48. package/dist/claude/hooks.js.map +1 -1
  49. package/dist/claude/init.d.ts +12 -1
  50. package/dist/claude/init.d.ts.map +1 -1
  51. package/dist/claude/init.js +48 -19
  52. package/dist/claude/init.js.map +1 -1
  53. package/dist/claude/session-metrics.d.ts +1 -1
  54. package/dist/claude/session-metrics.d.ts.map +1 -1
  55. package/dist/claude/session-metrics.js +11 -8
  56. package/dist/claude/session-metrics.js.map +1 -1
  57. package/dist/claude/settings-merge.d.ts +1 -0
  58. package/dist/claude/settings-merge.d.ts.map +1 -1
  59. package/dist/claude/settings-merge.js +21 -18
  60. package/dist/claude/settings-merge.js.map +1 -1
  61. package/dist/claude/shim-template.d.ts +17 -2
  62. package/dist/claude/shim-template.d.ts.map +1 -1
  63. package/dist/claude/shim-template.js +116 -22
  64. package/dist/claude/shim-template.js.map +1 -1
  65. package/dist/claude/skill-template.d.ts +10 -1
  66. package/dist/claude/skill-template.d.ts.map +1 -1
  67. package/dist/claude/skill-template.js +132 -1
  68. package/dist/claude/skill-template.js.map +1 -1
  69. package/dist/claude/state.d.ts +8 -0
  70. package/dist/claude/state.d.ts.map +1 -1
  71. package/dist/claude/state.js.map +1 -1
  72. package/dist/claude/statusline.d.ts.map +1 -1
  73. package/dist/claude/statusline.js +4 -1
  74. package/dist/claude/statusline.js.map +1 -1
  75. package/dist/claude/tally.js +1 -1
  76. package/dist/claude/tally.js.map +1 -1
  77. package/dist/cli-epilogue.d.ts +0 -6
  78. package/dist/cli-epilogue.d.ts.map +1 -1
  79. package/dist/cli-epilogue.js +5 -4
  80. package/dist/cli-epilogue.js.map +1 -1
  81. package/dist/cli-meta.d.ts +8 -0
  82. package/dist/cli-meta.d.ts.map +1 -1
  83. package/dist/cli-meta.js +28 -8
  84. package/dist/cli-meta.js.map +1 -1
  85. package/dist/cli-picker.d.ts.map +1 -1
  86. package/dist/cli-picker.js +11 -7
  87. package/dist/cli-picker.js.map +1 -1
  88. package/dist/cli.d.ts +0 -5
  89. package/dist/cli.d.ts.map +1 -1
  90. package/dist/cli.js +1037 -595
  91. package/dist/cli.js.map +1 -1
  92. package/dist/cloud/diff.d.ts +18 -0
  93. package/dist/cloud/diff.d.ts.map +1 -0
  94. package/dist/cloud/diff.js +58 -0
  95. package/dist/cloud/diff.js.map +1 -0
  96. package/dist/cloud/nudge.d.ts +66 -0
  97. package/dist/cloud/nudge.d.ts.map +1 -0
  98. package/dist/cloud/nudge.js +269 -0
  99. package/dist/cloud/nudge.js.map +1 -0
  100. package/dist/cloud/workspace-sync.d.ts +58 -0
  101. package/dist/cloud/workspace-sync.d.ts.map +1 -0
  102. package/dist/cloud/workspace-sync.js +268 -0
  103. package/dist/cloud/workspace-sync.js.map +1 -0
  104. package/dist/cloud/workspace.d.ts +159 -0
  105. package/dist/cloud/workspace.d.ts.map +1 -0
  106. package/dist/cloud/workspace.js +134 -0
  107. package/dist/cloud/workspace.js.map +1 -0
  108. package/dist/context/check.d.ts +1 -1
  109. package/dist/context/check.d.ts.map +1 -1
  110. package/dist/context/check.js +9 -8
  111. package/dist/context/check.js.map +1 -1
  112. package/dist/context/node-file.js +1 -1
  113. package/dist/context/node-file.js.map +1 -1
  114. package/dist/context/savings.d.ts.map +1 -1
  115. package/dist/context/savings.js +10 -7
  116. package/dist/context/savings.js.map +1 -1
  117. package/dist/engine.d.ts.map +1 -1
  118. package/dist/engine.js +3 -1
  119. package/dist/engine.js.map +1 -1
  120. package/dist/graph/build.d.ts +30 -0
  121. package/dist/graph/build.d.ts.map +1 -1
  122. package/dist/graph/build.js +65 -19
  123. package/dist/graph/build.js.map +1 -1
  124. package/dist/graph/cards.d.ts.map +1 -1
  125. package/dist/graph/cards.js +4 -2
  126. package/dist/graph/cards.js.map +1 -1
  127. package/dist/graph/check.d.ts.map +1 -1
  128. package/dist/graph/check.js +17 -18
  129. package/dist/graph/check.js.map +1 -1
  130. package/dist/graph/container.d.ts.map +1 -1
  131. package/dist/graph/container.js +7 -2
  132. package/dist/graph/container.js.map +1 -1
  133. package/dist/graph/extract-cache.d.ts +4 -0
  134. package/dist/graph/extract-cache.d.ts.map +1 -1
  135. package/dist/graph/extract-cache.js.map +1 -1
  136. package/dist/graph/extract.d.ts +2 -0
  137. package/dist/graph/extract.d.ts.map +1 -1
  138. package/dist/graph/extract.js +5 -32
  139. package/dist/graph/extract.js.map +1 -1
  140. package/dist/graph/generic.d.ts +7 -1
  141. package/dist/graph/generic.d.ts.map +1 -1
  142. package/dist/graph/generic.js +48 -8
  143. package/dist/graph/generic.js.map +1 -1
  144. package/dist/graph/native.d.ts +38 -0
  145. package/dist/graph/native.d.ts.map +1 -0
  146. package/dist/graph/native.js +169 -0
  147. package/dist/graph/native.js.map +1 -0
  148. package/dist/graph/refresh.d.ts.map +1 -1
  149. package/dist/graph/refresh.js +3 -2
  150. package/dist/graph/refresh.js.map +1 -1
  151. package/dist/graph/traverse-cli.d.ts.map +1 -1
  152. package/dist/graph/traverse-cli.js +4 -3
  153. package/dist/graph/traverse-cli.js.map +1 -1
  154. package/dist/graph/workspace-cli.d.ts +2 -0
  155. package/dist/graph/workspace-cli.d.ts.map +1 -1
  156. package/dist/graph/workspace-cli.js +13 -1
  157. package/dist/graph/workspace-cli.js.map +1 -1
  158. package/dist/graph/workspace.d.ts.map +1 -1
  159. package/dist/graph/workspace.js +6 -5
  160. package/dist/graph/workspace.js.map +1 -1
  161. package/dist/hosts/antigravity.d.ts +10 -3
  162. package/dist/hosts/antigravity.d.ts.map +1 -1
  163. package/dist/hosts/antigravity.js +27 -10
  164. package/dist/hosts/antigravity.js.map +1 -1
  165. package/dist/hosts/claude-global.d.ts +27 -4
  166. package/dist/hosts/claude-global.d.ts.map +1 -1
  167. package/dist/hosts/claude-global.js +90 -9
  168. package/dist/hosts/claude-global.js.map +1 -1
  169. package/dist/hosts/codex-hooks.d.ts.map +1 -1
  170. package/dist/hosts/codex-hooks.js +1 -2
  171. package/dist/hosts/codex-hooks.js.map +1 -1
  172. package/dist/hosts/config-write.d.ts.map +1 -1
  173. package/dist/hosts/config-write.js +2 -1
  174. package/dist/hosts/config-write.js.map +1 -1
  175. package/dist/hosts/cursor-hooks.d.ts +5 -2
  176. package/dist/hosts/cursor-hooks.d.ts.map +1 -1
  177. package/dist/hosts/cursor-hooks.js +14 -9
  178. package/dist/hosts/cursor-hooks.js.map +1 -1
  179. package/dist/hosts/init.d.ts +3 -0
  180. package/dist/hosts/init.d.ts.map +1 -1
  181. package/dist/hosts/init.js +32 -10
  182. package/dist/hosts/init.js.map +1 -1
  183. package/dist/hosts/instructions.d.ts +9 -4
  184. package/dist/hosts/instructions.d.ts.map +1 -1
  185. package/dist/hosts/instructions.js +19 -16
  186. package/dist/hosts/instructions.js.map +1 -1
  187. package/dist/hosts/mcp-config.d.ts +19 -4
  188. package/dist/hosts/mcp-config.d.ts.map +1 -1
  189. package/dist/hosts/mcp-config.js +81 -30
  190. package/dist/hosts/mcp-config.js.map +1 -1
  191. package/dist/hosts/plan.d.ts.map +1 -1
  192. package/dist/hosts/plan.js +11 -9
  193. package/dist/hosts/plan.js.map +1 -1
  194. package/dist/hosts/registry.d.ts +25 -2
  195. package/dist/hosts/registry.d.ts.map +1 -1
  196. package/dist/hosts/registry.js +53 -0
  197. package/dist/hosts/registry.js.map +1 -1
  198. package/dist/hosts/retract.d.ts.map +1 -1
  199. package/dist/hosts/retract.js +73 -33
  200. package/dist/hosts/retract.js.map +1 -1
  201. package/dist/hosts/sections.d.ts +17 -1
  202. package/dist/hosts/sections.d.ts.map +1 -1
  203. package/dist/hosts/sections.js +52 -2
  204. package/dist/hosts/sections.js.map +1 -1
  205. package/dist/mcp/instructions.d.ts +1 -25
  206. package/dist/mcp/instructions.d.ts.map +1 -1
  207. package/dist/mcp/instructions.js +6 -4
  208. package/dist/mcp/instructions.js.map +1 -1
  209. package/dist/mcp/server.d.ts.map +1 -1
  210. package/dist/mcp/server.js +7 -3
  211. package/dist/mcp/server.js.map +1 -1
  212. package/dist/mcp/tool-names.d.ts +10 -3
  213. package/dist/mcp/tool-names.d.ts.map +1 -1
  214. package/dist/mcp/tool-names.js +13 -5
  215. package/dist/mcp/tool-names.js.map +1 -1
  216. package/dist/mcp/tools.d.ts.map +1 -1
  217. package/dist/mcp/tools.js +6 -5
  218. package/dist/mcp/tools.js.map +1 -1
  219. package/dist/notes/ask-notes.d.ts +8 -0
  220. package/dist/notes/ask-notes.d.ts.map +1 -0
  221. package/dist/notes/ask-notes.js +18 -0
  222. package/dist/notes/ask-notes.js.map +1 -0
  223. package/dist/notes/branches.d.ts +85 -0
  224. package/dist/notes/branches.d.ts.map +1 -0
  225. package/dist/notes/branches.js +238 -0
  226. package/dist/notes/branches.js.map +1 -0
  227. package/dist/notes/cold-start.d.ts +127 -0
  228. package/dist/notes/cold-start.d.ts.map +1 -0
  229. package/dist/notes/cold-start.js +476 -0
  230. package/dist/notes/cold-start.js.map +1 -0
  231. package/dist/notes/git-facts.d.ts +17 -0
  232. package/dist/notes/git-facts.d.ts.map +1 -0
  233. package/dist/notes/git-facts.js +117 -0
  234. package/dist/notes/git-facts.js.map +1 -0
  235. package/dist/notes/home.d.ts +87 -0
  236. package/dist/notes/home.d.ts.map +1 -0
  237. package/dist/notes/home.js +423 -0
  238. package/dist/notes/home.js.map +1 -0
  239. package/dist/notes/notes.d.ts +178 -0
  240. package/dist/notes/notes.d.ts.map +1 -0
  241. package/dist/notes/notes.js +498 -0
  242. package/dist/notes/notes.js.map +1 -0
  243. package/dist/notes/repo-trail.d.ts +16 -0
  244. package/dist/notes/repo-trail.d.ts.map +1 -0
  245. package/dist/notes/repo-trail.js +74 -0
  246. package/dist/notes/repo-trail.js.map +1 -0
  247. package/dist/notes/session-cost.d.ts +21 -0
  248. package/dist/notes/session-cost.d.ts.map +1 -0
  249. package/dist/notes/session-cost.js +162 -0
  250. package/dist/notes/session-cost.js.map +1 -0
  251. package/dist/search/grep-cli.d.ts.map +1 -1
  252. package/dist/search/grep-cli.js +4 -3
  253. package/dist/search/grep-cli.js.map +1 -1
  254. package/dist/skills/skills.d.ts +118 -0
  255. package/dist/skills/skills.d.ts.map +1 -0
  256. package/dist/skills/skills.js +370 -0
  257. package/dist/skills/skills.js.map +1 -0
  258. package/dist/telemetry/contract.d.ts +2 -14
  259. package/dist/telemetry/contract.d.ts.map +1 -1
  260. package/dist/telemetry/contract.js +39 -24
  261. package/dist/telemetry/contract.js.map +1 -1
  262. package/dist/telemetry/gate.d.ts.map +1 -1
  263. package/dist/telemetry/gate.js +2 -1
  264. package/dist/telemetry/gate.js.map +1 -1
  265. package/dist/telemetry/notice.d.ts +1 -1
  266. package/dist/telemetry/notice.d.ts.map +1 -1
  267. package/dist/telemetry/notice.js +6 -5
  268. package/dist/telemetry/notice.js.map +1 -1
  269. package/dist/telemetry/track.d.ts.map +1 -1
  270. package/dist/telemetry/track.js +5 -0
  271. package/dist/telemetry/track.js.map +1 -1
  272. package/dist/upkeep-run.d.ts +7 -0
  273. package/dist/upkeep-run.d.ts.map +1 -1
  274. package/dist/upkeep-run.js +52 -12
  275. package/dist/upkeep-run.js.map +1 -1
  276. package/dist/upkeep.d.ts +9 -19
  277. package/dist/upkeep.d.ts.map +1 -1
  278. package/dist/upkeep.js +38 -59
  279. package/dist/upkeep.js.map +1 -1
  280. package/dist/util/browser.d.ts +3 -0
  281. package/dist/util/browser.d.ts.map +1 -0
  282. package/dist/util/browser.js +14 -0
  283. package/dist/util/browser.js.map +1 -0
  284. package/dist/util/front-matter.d.ts +19 -0
  285. package/dist/util/front-matter.d.ts.map +1 -0
  286. package/dist/util/front-matter.js +21 -0
  287. package/dist/util/front-matter.js.map +1 -0
  288. package/dist/util/state.d.ts +1 -18
  289. package/dist/util/state.d.ts.map +1 -1
  290. package/dist/util/state.js +4 -2
  291. package/dist/util/state.js.map +1 -1
  292. package/dist/viz/assemble.js +1 -1
  293. package/dist/viz/assemble.js.map +1 -1
  294. package/dist/viz/serve.d.ts.map +1 -1
  295. package/dist/viz/serve.js +4 -3
  296. package/dist/viz/serve.js.map +1 -1
  297. package/package.json +7 -7
  298. package/scripts/pack-trail.mjs +53 -0
  299. package/scripts/postinstall.mjs +17 -2
  300. package/scripts/run-tests.mjs +4 -1
  301. package/dist/brain/attach.d.ts +0 -44
  302. package/dist/brain/attach.d.ts.map +0 -1
  303. package/dist/brain/attach.js +0 -63
  304. package/dist/brain/attach.js.map +0 -1
  305. package/dist/brain/claude-md.d.ts +0 -61
  306. package/dist/brain/claude-md.d.ts.map +0 -1
  307. package/dist/brain/claude-md.js +0 -171
  308. package/dist/brain/claude-md.js.map +0 -1
  309. package/dist/brain/connect.d.ts +0 -59
  310. package/dist/brain/connect.d.ts.map +0 -1
  311. package/dist/brain/connect.js +0 -80
  312. package/dist/brain/connect.js.map +0 -1
  313. package/dist/brain/context-files.d.ts +0 -79
  314. package/dist/brain/context-files.d.ts.map +0 -1
  315. package/dist/brain/context-files.js +0 -245
  316. package/dist/brain/context-files.js.map +0 -1
  317. package/dist/brain/link.d.ts +0 -106
  318. package/dist/brain/link.d.ts.map +0 -1
  319. package/dist/brain/link.js +0 -167
  320. package/dist/brain/link.js.map +0 -1
  321. package/dist/brain/pull.d.ts +0 -17
  322. package/dist/brain/pull.d.ts.map +0 -1
  323. package/dist/brain/pull.js +0 -172
  324. package/dist/brain/pull.js.map +0 -1
  325. package/dist/brain/push.d.ts +0 -155
  326. package/dist/brain/push.d.ts.map +0 -1
  327. package/dist/brain/push.js +0 -304
  328. package/dist/brain/push.js.map +0 -1
  329. package/dist/brain/signup.d.ts +0 -117
  330. package/dist/brain/signup.d.ts.map +0 -1
  331. package/dist/brain/signup.js +0 -276
  332. package/dist/brain/signup.js.map +0 -1
  333. package/dist/brain/upload.d.ts +0 -61
  334. package/dist/brain/upload.d.ts.map +0 -1
  335. package/dist/brain/upload.js +0 -210
  336. package/dist/brain/upload.js.map +0 -1
  337. package/dist/brain/watch.d.ts +0 -209
  338. package/dist/brain/watch.d.ts.map +0 -1
  339. package/dist/brain/watch.js +0 -396
  340. package/dist/brain/watch.js.map +0 -1
  341. package/dist/brain/wire.d.ts +0 -38
  342. package/dist/brain/wire.d.ts.map +0 -1
  343. package/dist/brain/wire.js +0 -133
  344. package/dist/brain/wire.js.map +0 -1
  345. package/dist/legacy-args.d.ts +0 -12
  346. package/dist/legacy-args.d.ts.map +0 -1
  347. package/dist/legacy-args.js +0 -31
  348. package/dist/legacy-args.js.map +0 -1
@@ -1,171 +0,0 @@
1
- /**
2
- * The CLAUDE.md half of `graft trail pull` (and of `graft claude-md pull`, its
3
- * old name): write the CLAUDE.md changes accepted in Trail into this checkout's
4
- * instruction file.
5
- *
6
- * Trail compares the repository's CLAUDE.md with what its history says and
7
- * suggests edits and new sections; a person accepts some of them on the brain's
8
- * CLAUDE.md page. This fetches the accepted ones, applies them to the local
9
- * file, and tells Trail which it wrote so the page stops listing them.
10
- *
11
- * The file is edited line by line, never regenerated, so everything a change
12
- * does not touch comes back byte for byte. An edit whose text is no longer in
13
- * its section means the local file has moved on since Trail read it; that
14
- * change is reported and left, never guessed at. Same rules as Trail's own
15
- * ComposeClaudeMd, which is what the page's preview shows.
16
- */
17
- import { baseUrlFor } from "./link.js";
18
- /** GET /api/public/brains/:id/claude-md — the accepted changes. */
19
- export async function fetchAcceptedChanges(link, fetchImpl = fetch) {
20
- const url = `${baseUrlFor(link)}/api/public/brains/${encodeURIComponent(link.brainId)}/claude-md`;
21
- try {
22
- const res = await fetchImpl(url, {
23
- headers: { authorization: `Bearer ${link.token}`, accept: "application/json" },
24
- signal: AbortSignal.timeout(15_000),
25
- });
26
- const body = await res.text();
27
- if (res.status === 404 || res.status === 503) {
28
- return { error: "this trail has no CLAUDE.md suggestions yet — its Trail may be older than the feature", unsupported: true };
29
- }
30
- if (!res.ok)
31
- return { error: `Trail refused the pull: ${res.status} ${body.slice(0, 200)}` };
32
- const parsed = JSON.parse(body);
33
- return { path: parsed.path ?? "", head_sha: parsed.head_sha ?? "", changes: parsed.changes ?? [] };
34
- }
35
- catch (e) {
36
- return { error: `could not reach Trail: ${e instanceof Error ? e.message : e}` };
37
- }
38
- }
39
- /** POST /api/public/brains/:id/claude-md/applied — what this pull wrote. */
40
- export async function markApplied(link, ids, fetchImpl = fetch) {
41
- if (ids.length === 0)
42
- return true;
43
- const url = `${baseUrlFor(link)}/api/public/brains/${encodeURIComponent(link.brainId)}/claude-md/applied`;
44
- try {
45
- // Trail takes at most 100 per request.
46
- for (let i = 0; i < ids.length; i += 100) {
47
- const res = await fetchImpl(url, {
48
- method: "POST",
49
- headers: {
50
- authorization: `Bearer ${link.token}`,
51
- "content-type": "application/json",
52
- accept: "application/json",
53
- },
54
- body: JSON.stringify({ ids: ids.slice(i, i + 100) }),
55
- signal: AbortSignal.timeout(15_000),
56
- });
57
- if (!res.ok)
58
- return false;
59
- }
60
- return true;
61
- }
62
- catch {
63
- return false;
64
- }
65
- }
66
- const HEADING = /^(#{1,6})\s+(.+?)\s*#*\s*$/;
67
- /** Every ATX heading outside code fences, with the lines it owns. */
68
- function sectionsOf(lines) {
69
- const heads = [];
70
- let fence = false;
71
- lines.forEach((ln, i) => {
72
- const t = ln.trim();
73
- if (t.startsWith("```") || t.startsWith("~~~")) {
74
- fence = !fence;
75
- return;
76
- }
77
- if (fence)
78
- return;
79
- const m = HEADING.exec(ln);
80
- if (m)
81
- heads.push({ line: i, level: m[1].length, title: m[2].trim() });
82
- });
83
- return heads.map((h, i) => {
84
- let end = lines.length;
85
- for (let j = i + 1; j < heads.length; j++) {
86
- if (heads[j].level <= h.level) {
87
- end = heads[j].line;
88
- break;
89
- }
90
- }
91
- return { title: h.title, level: h.level, head: h.line, end };
92
- });
93
- }
94
- const norm = (s) => s.trim().toLowerCase();
95
- /** Trim the blank lines a section ends with, so appended text sits under its content. */
96
- function lastContentLine(lines, s) {
97
- let i = s.end;
98
- while (i > s.head + 1 && lines[i - 1].trim() === "")
99
- i--;
100
- return i;
101
- }
102
- /**
103
- * Apply accepted changes to the file's text. Pure: reads nothing, writes
104
- * nothing, so the command and the tests share it.
105
- */
106
- export function applyChanges(original, changes) {
107
- const crlf = original.includes("\r\n");
108
- let lines = original.replace(/\r\n/g, "\n").split("\n");
109
- const out = { text: original, written: [], present: [], skipped: [] };
110
- // Edits first, against headings that exist; then additions, which may go
111
- // after a section an edit just touched.
112
- const ordered = [...changes.filter((c) => c.kind === "edit"), ...changes.filter((c) => c.kind === "add")];
113
- for (const c of ordered) {
114
- const sections = sectionsOf(lines);
115
- if (c.kind === "edit") {
116
- const s = sections.find((x) => norm(x.title) === norm(c.heading));
117
- if (!s) {
118
- out.skipped.push({ change: c, why: `no “${c.heading}” section in the file` });
119
- continue;
120
- }
121
- const body = lines.slice(s.head + 1, s.end).join("\n");
122
- const text = c.text.replace(/\r\n/g, "\n");
123
- const find = (c.find ?? "").replace(/\r\n/g, "\n");
124
- if (text.trim() && body.includes(text.trim())) {
125
- out.present.push(c);
126
- continue;
127
- }
128
- if (!find) {
129
- const at = lastContentLine(lines, s);
130
- lines = [...lines.slice(0, at), ...text.trimEnd().split("\n"), ...lines.slice(at)];
131
- out.written.push(c);
132
- continue;
133
- }
134
- const idx = body.indexOf(find);
135
- if (idx < 0) {
136
- out.skipped.push({ change: c, why: `the text it rewrites is no longer in “${c.heading}”` });
137
- continue;
138
- }
139
- const next = body.slice(0, idx) + text + body.slice(idx + find.length);
140
- lines = [...lines.slice(0, s.head + 1), ...next.split("\n"), ...lines.slice(s.end)];
141
- out.written.push(c);
142
- continue;
143
- }
144
- // add
145
- if (sections.some((x) => norm(x.title) === norm(c.heading))) {
146
- out.present.push(c);
147
- continue;
148
- }
149
- const block = [`## ${c.heading.trim()}`, "", ...c.text.replace(/\r\n/g, "\n").trim().split("\n")];
150
- const after = c.after_heading ? sections.find((x) => norm(x.title) === norm(c.after_heading)) : undefined;
151
- if (after) {
152
- const at = lastContentLine(lines, after);
153
- // A blank line either side, whatever the file had there.
154
- const tail = lines.slice(at);
155
- lines = [...lines.slice(0, at), "", ...block, ...(tail.length > 0 && tail[0].trim() !== "" ? [""] : []), ...tail];
156
- }
157
- else {
158
- while (lines.length > 0 && lines[lines.length - 1].trim() === "")
159
- lines.pop();
160
- lines = lines.length > 0 ? [...lines, "", ...block] : block;
161
- lines.push("");
162
- }
163
- out.written.push(c);
164
- }
165
- let text = lines.join("\n");
166
- if (out.written.length > 0 && !text.endsWith("\n"))
167
- text += "\n";
168
- out.text = out.written.length > 0 ? (crlf ? text.replace(/\n/g, "\r\n") : text) : original;
169
- return out;
170
- }
171
- //# sourceMappingURL=claude-md.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claude-md.js","sourceRoot":"","sources":["../../src/brain/claude-md.ts"],"names":[],"mappings":"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"}
@@ -1,59 +0,0 @@
1
- /**
2
- * The one command a user runs to attach a brain: parse the handoff value,
3
- * store the link, pull the rules, write them into the agent files.
4
- */
5
- import { type BrainLink, type BrainRule } from './link.js';
6
- import { type BrainWrite } from './wire.js';
7
- /**
8
- * Parse the `--trail` value.
9
- *
10
- * The onboarding page hands over one string so there is one thing to copy. Two
11
- * accepted shapes:
12
- *
13
- * `<brainId>:<token>` — the normal case, both halves in one paste
14
- * `<brainId>` — with the token in `GRAFT_BRAIN_TOKEN`, for CI, where
15
- * a secret must not appear in a command line
16
- *
17
- * A bare token with no brain id is rejected rather than guessed: pointing the
18
- * wrong brain at a repo would write another team's rules into it.
19
- */
20
- export declare function parseBrainArg(value: string): BrainLink | {
21
- error: string;
22
- };
23
- /** What connecting a brain did, for the caller to print. */
24
- export interface ConnectResult {
25
- linked: boolean;
26
- ruleCount: number;
27
- writes: BrainWrite[];
28
- /** Set when the rules could not be fetched; the link is still stored. */
29
- warning?: string;
30
- }
31
- /**
32
- * Store the link, pull the rules once, and write them into the agent files.
33
- *
34
- * The link is stored even when the pull fails. That is deliberate: a token
35
- * typed correctly against a brain that is momentarily unreachable should not
36
- * have to be pasted again — `graft trail pull` retries, and `ask` degrades to
37
- * the code-only answer meanwhile.
38
- */
39
- export declare function connectBrain(repo: string, link: BrainLink, opts?: {
40
- home: string;
41
- ids?: string[];
42
- fetchImpl?: typeof fetch;
43
- }): Promise<ConnectResult>;
44
- /**
45
- * Re-pull the rules for an already-linked repo and rewrite the agent files.
46
- * Returns null when the repo has no brain linked.
47
- */
48
- export declare function pullBrain(repo: string, opts: {
49
- home: string;
50
- ids?: string[];
51
- fetchImpl?: typeof fetch;
52
- }): Promise<ConnectResult | null>;
53
- /** The linked brain and its cached rule set, for `graft trail status`. */
54
- export declare function brainStatus(repo: string): {
55
- link: BrainLink | null;
56
- rules: BrainRule[];
57
- fetchedAt: number | null;
58
- };
59
- //# sourceMappingURL=connect.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/brain/connect.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAML,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAGhE;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAkB1E;AAED,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,EACf,IAAI,GAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAAiB,GAC9E,OAAO,CAAC,aAAa,CAAC,CAexB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAAE,GAC/D,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAI/B;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG;IACzC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAIA"}
@@ -1,80 +0,0 @@
1
- /**
2
- * The one command a user runs to attach a brain: parse the handoff value,
3
- * store the link, pull the rules, write them into the agent files.
4
- */
5
- import { readLink, writeLink, fetchRules, writeRulesCache, readRulesCache, } from './link.js';
6
- import { writeBrainSections } from './wire.js';
7
- import { basename } from 'node:path';
8
- /**
9
- * Parse the `--trail` value.
10
- *
11
- * The onboarding page hands over one string so there is one thing to copy. Two
12
- * accepted shapes:
13
- *
14
- * `<brainId>:<token>` — the normal case, both halves in one paste
15
- * `<brainId>` — with the token in `GRAFT_BRAIN_TOKEN`, for CI, where
16
- * a secret must not appear in a command line
17
- *
18
- * A bare token with no brain id is rejected rather than guessed: pointing the
19
- * wrong brain at a repo would write another team's rules into it.
20
- */
21
- export function parseBrainArg(value) {
22
- const raw = value.trim();
23
- if (!raw)
24
- return { error: 'empty --trail value' };
25
- const cut = raw.indexOf(':');
26
- if (cut > 0) {
27
- const brainId = raw.slice(0, cut).trim();
28
- const token = raw.slice(cut + 1).trim();
29
- if (!brainId || !token)
30
- return { error: 'expected --trail <brainId>:<token>' };
31
- return { brainId, token };
32
- }
33
- const envToken = process.env.GRAFT_BRAIN_TOKEN;
34
- if (!envToken) {
35
- return {
36
- error: 'expected --trail <brainId>:<token>, or a bare brain id with the token in GRAFT_BRAIN_TOKEN',
37
- };
38
- }
39
- return { brainId: raw, token: envToken };
40
- }
41
- /**
42
- * Store the link, pull the rules once, and write them into the agent files.
43
- *
44
- * The link is stored even when the pull fails. That is deliberate: a token
45
- * typed correctly against a brain that is momentarily unreachable should not
46
- * have to be pasted again — `graft trail pull` retries, and `ask` degrades to
47
- * the code-only answer meanwhile.
48
- */
49
- export async function connectBrain(repo, link, opts = { home: '' }) {
50
- writeLink(repo, link);
51
- const rules = await fetchRules(link, opts.fetchImpl ?? fetch);
52
- if (rules === null) {
53
- return {
54
- linked: true,
55
- ruleCount: 0,
56
- writes: [],
57
- warning: 'could not reach the brain to pull its rules — the link is saved; run `graft trail pull` to retry',
58
- };
59
- }
60
- writeRulesCache(repo, { brainId: link.brainId, fetchedAt: Date.now(), rules });
61
- const writes = writeBrainSections(repo, opts.home, rules, basename(repo), opts.ids);
62
- return { linked: true, ruleCount: rules.length, writes };
63
- }
64
- /**
65
- * Re-pull the rules for an already-linked repo and rewrite the agent files.
66
- * Returns null when the repo has no brain linked.
67
- */
68
- export async function pullBrain(repo, opts) {
69
- const link = readLink(repo);
70
- if (!link)
71
- return null;
72
- return connectBrain(repo, link, opts);
73
- }
74
- /** The linked brain and its cached rule set, for `graft trail status`. */
75
- export function brainStatus(repo) {
76
- const link = readLink(repo);
77
- const cache = readRulesCache(repo);
78
- return { link, rules: cache?.rules ?? [], fetchedAt: cache?.fetchedAt ?? null };
79
- }
80
- //# sourceMappingURL=connect.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/brain/connect.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,UAAU,EACV,eAAe,EACf,cAAc,GAGf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,kBAAkB,EAAmB,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAClD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC;QAC/E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC/C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,KAAK,EACH,4FAA4F;SAC/F,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC3C,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAY,EACZ,IAAe,EACf,OAAmE,EAAE,IAAI,EAAE,EAAE,EAAE;IAE/E,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtB,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;IAC9D,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,EAAE;YACV,OAAO,EACL,kGAAkG;SACrG,CAAC;IACJ,CAAC;IACD,eAAe,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IACpF,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAY,EACZ,IAAgE;IAEhE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,WAAW,CAAC,IAAY;IAKtC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,IAAI,EAAE,CAAC;AAClF,CAAC"}
@@ -1,79 +0,0 @@
1
- import { type BrainLink } from "./link.js";
2
- export type ContextFileKind = "agents_md" | "folder_claude_md" | "cursor_rule" | "skill";
3
- /** One accepted change to one context file. */
4
- export interface ContextFileChange {
5
- id: string;
6
- kind: "edit" | "add" | "create" | "replace";
7
- heading?: string;
8
- after_heading?: string;
9
- find?: string;
10
- /** edit/add: as in claude-md.ts. create/replace: the whole file. For
11
- * replace, `find` is the whole file the suggestion was computed against. */
12
- text: string;
13
- reason?: string;
14
- }
15
- export interface ContextFile {
16
- kind: ContextFileKind | string;
17
- path: string;
18
- exists?: boolean;
19
- managed_by_graft?: boolean;
20
- changes: ContextFileChange[];
21
- }
22
- export interface ContextFilesPull {
23
- head_sha: string;
24
- files: ContextFile[];
25
- }
26
- /** The kind of a context file, from its path — for the root CLAUDE.md pull,
27
- * which names a path but no kind. */
28
- export declare function kindForPath(path: string): string;
29
- /**
30
- * Whether a file of `kind` is for one of the `wired` agents. Everything passes
31
- * when nothing is wired — there is no choice to respect — and so does a kind
32
- * graft does not know, rather than dropping what Trail sent.
33
- */
34
- export declare function readByWired(kind: string, wired: readonly string[]): boolean;
35
- /** The agents among `wired` that read a file of `kind`. */
36
- export declare function readersOf(kind: string, wired: readonly string[]): string[];
37
- /** GET /api/public/brains/:id/context-files. `unsupported` on a 404: an older Trail. */
38
- export declare function fetchContextFiles(link: BrainLink, fetchImpl?: typeof fetch): Promise<ContextFilesPull | {
39
- unsupported: true;
40
- } | {
41
- error: string;
42
- }>;
43
- /** POST /api/public/brains/:id/context-files/applied, 100 ids per request. */
44
- export declare function markContextFilesApplied(link: BrainLink, ids: string[], fetchImpl?: typeof fetch): Promise<boolean>;
45
- /** What a pull will do (or did) to one file. */
46
- export interface FilePlan {
47
- /** Repo-relative, forward slashes. */
48
- path: string;
49
- /** M: an existing file changes. A: a new file. "": nothing to write. */
50
- status: "M" | "A" | "";
51
- /** The file's new text, when status is set. */
52
- text?: string;
53
- written: ContextFileChange[];
54
- /** Already there: counts as applied, nothing to write. */
55
- present: ContextFileChange[];
56
- skipped: Array<{
57
- change: ContextFileChange;
58
- why: string;
59
- }>;
60
- }
61
- /**
62
- * The repo-relative form of a path Trail sent, or null when it points
63
- * anywhere but a file inside this checkout. Trail is trusted to suggest text,
64
- * not to choose where on this machine it lands.
65
- */
66
- export declare function safeRelPath(root: string, path: string): string | null;
67
- /**
68
- * Work out one file's changes against what is on disk. Pure but for reading
69
- * the file, so the command, the dry run and the tests share it.
70
- */
71
- export declare function planContextFile(root: string, file: ContextFile): FilePlan;
72
- /** Write a planned file, making its folder when it is new. */
73
- export declare function writePlannedFile(root: string, plan: FilePlan): void;
74
- /** `+ Money · ~ Commands` — a new section is +, an edited one ~, a whole file nothing. */
75
- export declare function changeSummary(changes: Array<{
76
- kind: string;
77
- heading?: string;
78
- }>): string;
79
- //# sourceMappingURL=context-files.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-files.d.ts","sourceRoot":"","sources":["../../src/brain/context-files.ts"],"names":[],"mappings":"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"}
@@ -1,245 +0,0 @@
1
- /**
2
- * `graft trail pull`, for every context file rather than only the root CLAUDE.md.
3
- *
4
- * Trail suggests changes to the files a repository hands its coding agents —
5
- * AGENTS.md, a folder's own CLAUDE.md, Cursor rules, Claude skills — and a
6
- * person accepts some of them. This fetches the accepted ones and writes them.
7
- *
8
- * Edits and new sections go through the same line-by-line patcher as the root
9
- * CLAUDE.md (see claude-md.ts), so everything a change does not name comes back
10
- * byte for byte. A `create` carries a whole file, and it is never allowed to
11
- * overwrite a file someone wrote here: an existing file with other content is a
12
- * conflict to report, unless graft itself owns that file. A `replace` (how a
13
- * Cursor rule is edited) carries the whole new file and the whole file it was
14
- * computed against, and is written only while the file here is still that one.
15
- */
16
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17
- import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
18
- import { applyChanges } from "./claude-md.js";
19
- import { baseUrlFor } from "./link.js";
20
- /**
21
- * Which picked agents read a file of this kind. A file whose readers were not
22
- * picked is neither listed nor written: `graft init` is where someone said which
23
- * agents this repo is for, and a pull must not quietly add files for others.
24
- */
25
- const READERS = {
26
- claude_md: ["claude"],
27
- folder_claude_md: ["claude"],
28
- skill: ["claude"],
29
- agents_md: ["agents", "hermes", "antigravity"],
30
- cursor_rule: ["cursor"],
31
- };
32
- /** The kind of a context file, from its path — for the root CLAUDE.md pull,
33
- * which names a path but no kind. */
34
- export function kindForPath(path) {
35
- const p = path.replace(/\\/g, "/");
36
- const name = p.split("/").pop() ?? "";
37
- if (name === "CLAUDE.md")
38
- return p.includes("/") ? "folder_claude_md" : "claude_md";
39
- if (name === "AGENTS.md")
40
- return "agents_md";
41
- if (p.startsWith(".cursor/rules/"))
42
- return "cursor_rule";
43
- if (p.startsWith(".claude/skills/"))
44
- return "skill";
45
- return "";
46
- }
47
- /**
48
- * Whether a file of `kind` is for one of the `wired` agents. Everything passes
49
- * when nothing is wired — there is no choice to respect — and so does a kind
50
- * graft does not know, rather than dropping what Trail sent.
51
- */
52
- export function readByWired(kind, wired) {
53
- if (wired.length === 0)
54
- return true;
55
- const readers = READERS[kind];
56
- if (!readers)
57
- return true;
58
- return readers.some((r) => wired.includes(r));
59
- }
60
- /** The agents among `wired` that read a file of `kind`. */
61
- export function readersOf(kind, wired) {
62
- const readers = READERS[kind] ?? [];
63
- return wired.filter((w) => readers.includes(w));
64
- }
65
- /** GET /api/public/brains/:id/context-files. `unsupported` on a 404: an older Trail. */
66
- export async function fetchContextFiles(link, fetchImpl = fetch) {
67
- const url = `${baseUrlFor(link)}/api/public/brains/${encodeURIComponent(link.brainId)}/context-files`;
68
- try {
69
- const res = await fetchImpl(url, {
70
- headers: { authorization: `Bearer ${link.token}`, accept: "application/json" },
71
- signal: AbortSignal.timeout(15_000),
72
- });
73
- const body = await res.text();
74
- if (res.status === 404)
75
- return { unsupported: true };
76
- if (!res.ok)
77
- return { error: `Trail refused the pull: ${res.status} ${body.slice(0, 200)}` };
78
- const parsed = JSON.parse(body);
79
- const files = Array.isArray(parsed.files) ? parsed.files : [];
80
- return {
81
- head_sha: String(parsed.head_sha ?? ""),
82
- files: files
83
- .filter((f) => f && typeof f.path === "string")
84
- .map((f) => ({ ...f, changes: Array.isArray(f.changes) ? f.changes : [] })),
85
- };
86
- }
87
- catch (e) {
88
- return { error: `could not reach Trail: ${e instanceof Error ? e.message : e}` };
89
- }
90
- }
91
- /** POST /api/public/brains/:id/context-files/applied, 100 ids per request. */
92
- export async function markContextFilesApplied(link, ids, fetchImpl = fetch) {
93
- if (ids.length === 0)
94
- return true;
95
- const url = `${baseUrlFor(link)}/api/public/brains/${encodeURIComponent(link.brainId)}/context-files/applied`;
96
- try {
97
- for (let i = 0; i < ids.length; i += 100) {
98
- const res = await fetchImpl(url, {
99
- method: "POST",
100
- headers: {
101
- authorization: `Bearer ${link.token}`,
102
- "content-type": "application/json",
103
- accept: "application/json",
104
- },
105
- body: JSON.stringify({ ids: ids.slice(i, i + 100) }),
106
- signal: AbortSignal.timeout(15_000),
107
- });
108
- if (!res.ok)
109
- return false;
110
- }
111
- return true;
112
- }
113
- catch {
114
- return false;
115
- }
116
- }
117
- /**
118
- * The repo-relative form of a path Trail sent, or null when it points
119
- * anywhere but a file inside this checkout. Trail is trusted to suggest text,
120
- * not to choose where on this machine it lands.
121
- */
122
- export function safeRelPath(root, path) {
123
- const raw = path.replace(/\\/g, "/").trim();
124
- if (!raw || isAbsolute(raw) || /^[a-zA-Z]:/.test(raw))
125
- return null;
126
- const parts = raw.split("/");
127
- if (parts.some((p) => p === ".." || p === ""))
128
- return null;
129
- if (parts[0] === ".git")
130
- return null;
131
- const abs = resolve(root, normalize(raw));
132
- const rel = relative(resolve(root), abs);
133
- if (!rel || rel.startsWith("..") || isAbsolute(rel))
134
- return null;
135
- return rel.split(sep).join("/");
136
- }
137
- /**
138
- * Work out one file's changes against what is on disk. Pure but for reading
139
- * the file, so the command, the dry run and the tests share it.
140
- */
141
- export function planContextFile(root, file) {
142
- const rel = safeRelPath(root, file.path);
143
- const plan = { path: rel ?? file.path, status: "", written: [], present: [], skipped: [] };
144
- if (!rel) {
145
- for (const c of file.changes)
146
- plan.skipped.push({ change: c, why: "the path points outside this repo" });
147
- return plan;
148
- }
149
- const abs = join(root, rel);
150
- const existed = existsSync(abs);
151
- let original = "";
152
- if (existed) {
153
- try {
154
- original = readFileSync(abs, "utf8");
155
- }
156
- catch {
157
- for (const c of file.changes)
158
- plan.skipped.push({ change: c, why: "the file here could not be read" });
159
- return plan;
160
- }
161
- }
162
- let text = original;
163
- let changed = false;
164
- // Whole files first; the edits and sections after them may be relative to one.
165
- for (const c of file.changes.filter((x) => x.kind === "create")) {
166
- const want = c.text.replace(/\r\n/g, "\n");
167
- const have = text.replace(/\r\n/g, "\n");
168
- if (!existed && !changed) {
169
- text = c.text.endsWith("\n") ? c.text : `${c.text}\n`;
170
- changed = true;
171
- plan.written.push(c);
172
- }
173
- else if (have.trimEnd() === want.trimEnd()) {
174
- plan.present.push(c);
175
- }
176
- else if (file.managed_by_graft) {
177
- text = c.text.endsWith("\n") ? c.text : `${c.text}\n`;
178
- changed = true;
179
- plan.written.push(c);
180
- }
181
- else {
182
- plan.skipped.push({ change: c, why: "a file with other content is already there" });
183
- }
184
- }
185
- // Whole-file replacements, guarded by the text they were computed against.
186
- const same = (a, b) => a.replace(/\r\n/g, "\n").trimEnd() === b.replace(/\r\n/g, "\n").trimEnd();
187
- for (const c of file.changes.filter((x) => x.kind === "replace")) {
188
- if (same(text, c.text)) {
189
- plan.present.push(c);
190
- }
191
- else if (same(text, c.find ?? "") && (existed || changed || (c.find ?? "").trim() === "")) {
192
- text = c.text.endsWith("\n") ? c.text : `${c.text}\n`;
193
- changed = true;
194
- plan.written.push(c);
195
- }
196
- else {
197
- plan.skipped.push({ change: c, why: "the file changed here since Trail read it" });
198
- }
199
- }
200
- const patches = file.changes.filter((x) => x.kind === "edit" || x.kind === "add");
201
- if (patches.length > 0) {
202
- // A file that is not here yet is an empty one: an edit to a section of it
203
- // becomes that section, so the change lands rather than being skipped for
204
- // a heading nobody could have written.
205
- const fresh = !existed && !changed;
206
- const r = applyChanges(text, patches.map((c) => ({
207
- ...c,
208
- heading: c.heading ?? "",
209
- kind: fresh && c.kind === "edit" ? "add" : c.kind,
210
- ...(fresh && c.kind === "edit" ? { after_heading: "" } : {}),
211
- })));
212
- const byId = new Map(patches.map((c) => [c.id, c]));
213
- for (const w of r.written)
214
- plan.written.push(byId.get(w.id));
215
- for (const p of r.present)
216
- plan.present.push(byId.get(p.id));
217
- for (const s of r.skipped)
218
- plan.skipped.push({ change: byId.get(s.change.id), why: s.why });
219
- if (r.written.length > 0) {
220
- text = r.text;
221
- changed = true;
222
- }
223
- }
224
- if (changed && text !== original) {
225
- plan.status = existed ? "M" : "A";
226
- plan.text = text;
227
- }
228
- return plan;
229
- }
230
- /** Write a planned file, making its folder when it is new. */
231
- export function writePlannedFile(root, plan) {
232
- if (!plan.status || plan.text === undefined)
233
- return;
234
- const abs = join(root, plan.path);
235
- mkdirSync(dirname(abs), { recursive: true });
236
- writeFileSync(abs, plan.text);
237
- }
238
- /** `+ Money · ~ Commands` — a new section is +, an edited one ~, a whole file nothing. */
239
- export function changeSummary(changes) {
240
- return changes
241
- .filter((c) => c.kind === "add" || c.kind === "edit")
242
- .map((c) => `${c.kind === "add" ? "+" : "~"} ${c.heading ?? ""}`.trim())
243
- .join(" · ");
244
- }
245
- //# sourceMappingURL=context-files.js.map