@north-light/crouter 0.3.227 → 0.3.229

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 (312) hide show
  1. package/dist/api/client.d.ts +5 -5
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/dto/broker-ops.d.ts +8 -0
  4. package/dist/api/dto/memory.d.ts +8 -7
  5. package/dist/api/dto/memory.js +2 -2
  6. package/dist/builtin-memory/04-base-worker.md +1 -1
  7. package/dist/builtin-memory/insights/init.md +5 -5
  8. package/dist/builtin-memory/internal/INDEX.md +1 -1
  9. package/dist/builtin-memory/internal/agent-shaping.md +11 -11
  10. package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
  11. package/dist/builtin-memory/internal/memory-loading.md +6 -6
  12. package/dist/builtin-memory/internal/plugins.md +1 -1
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +50 -37
  14. package/dist/clients/attach/__tests__/pane-tag-successor.test.js +56 -0
  15. package/dist/clients/attach/__tests__/profile-files.test.js +21 -0
  16. package/dist/clients/attach/chrome/inbox-strip.js +11 -7
  17. package/dist/clients/attach/session/pane-tag.d.ts +28 -2
  18. package/dist/clients/attach/session/pane-tag.js +48 -22
  19. package/dist/clients/attach/session/profile-files.d.ts +6 -0
  20. package/dist/clients/attach/session/profile-files.js +44 -11
  21. package/dist/clients/attach/slash/dispatch.js +4 -7
  22. package/dist/clients/attach/viewer.js +588 -596
  23. package/dist/commands/__tests__/surface-reload-target.test.js +21 -0
  24. package/dist/commands/api-client.d.ts +3 -7
  25. package/dist/commands/api-client.js +7 -12
  26. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +292 -0
  27. package/dist/commands/memory/__tests__/repository-root-lint.test.js +146 -0
  28. package/dist/commands/memory/delete.js +51 -24
  29. package/dist/commands/memory/edit.js +50 -10
  30. package/dist/commands/memory/find.js +105 -56
  31. package/dist/commands/memory/history.js +51 -31
  32. package/dist/commands/memory/lint.d.ts +0 -9
  33. package/dist/commands/memory/lint.js +78 -322
  34. package/dist/commands/memory/list.d.ts +12 -4
  35. package/dist/commands/memory/list.js +64 -25
  36. package/dist/commands/memory/move.js +103 -73
  37. package/dist/commands/memory/origin.js +35 -5
  38. package/dist/commands/memory/read.d.ts +4 -0
  39. package/dist/commands/memory/read.js +132 -80
  40. package/dist/commands/memory/shared.d.ts +115 -25
  41. package/dist/commands/memory/shared.js +331 -74
  42. package/dist/commands/memory/write.js +72 -21
  43. package/dist/commands/memory.js +2 -2
  44. package/dist/commands/node/create.d.ts +1 -1
  45. package/dist/commands/node/create.js +1 -1
  46. package/dist/commands/node/inspect.js +1 -1
  47. package/dist/commands/node/lifecycle.js +5 -5
  48. package/dist/commands/pkg/market-manage.js +25 -24
  49. package/dist/commands/pkg/plugin-manage.d.ts +22 -6
  50. package/dist/commands/pkg/plugin-manage.js +118 -25
  51. package/dist/commands/pkg/shared.d.ts +8 -0
  52. package/dist/commands/pkg/shared.js +23 -20
  53. package/dist/commands/surface-reload.d.ts +5 -0
  54. package/dist/commands/surface-reload.js +9 -1
  55. package/dist/commands/sys/__tests__/migrate.test.js +1140 -22
  56. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +218 -0
  57. package/dist/commands/sys/migrate.js +126 -140
  58. package/dist/commands/sys/panels/profiles-panel.d.ts +66 -0
  59. package/dist/commands/sys/panels/profiles-panel.js +599 -0
  60. package/dist/commands/sys/settings-shell.d.ts +4 -2
  61. package/dist/commands/sys/settings-shell.js +35 -4
  62. package/dist/commands/sys/settings.js +21 -5
  63. package/dist/commands/sys/sync-deps.d.ts +2 -0
  64. package/dist/commands/sys/sync-deps.js +26 -15
  65. package/dist/commands/sys/sync-project-guidance.js +228 -145
  66. package/dist/commands/sys/sync-skills.js +28 -17
  67. package/dist/commands/sys/update.js +11 -3
  68. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +15 -2
  69. package/dist/core/__tests__/config-change-delta.test.js +106 -0
  70. package/dist/core/__tests__/context-intro.test.js +13 -9
  71. package/dist/core/__tests__/daemon-boot.test.js +22 -16
  72. package/dist/core/__tests__/fixtures/memory-slash-live-probe.js +5 -1
  73. package/dist/core/__tests__/human-deliver.test.js +19 -0
  74. package/dist/core/__tests__/inline-memory-refs.test.js +50 -46
  75. package/dist/core/__tests__/{serial → integration}/broker-fork-seam.test.js +1 -1
  76. package/dist/core/__tests__/{serial → integration}/broker-sdk-wiring.test.js +1 -1
  77. package/dist/core/__tests__/{serial → integration}/broker-snapshot-history.test.js +1 -1
  78. package/dist/core/__tests__/{serial → integration}/command-plugins.test.js +94 -3
  79. package/dist/core/__tests__/{serial → integration}/deferred-no-wake.test.js +1 -1
  80. package/dist/core/__tests__/{serial → integration}/flagship-lifecycle.test.js +13 -27
  81. package/dist/core/__tests__/{serial → integration}/host-teardown-process-group.test.js +1 -1
  82. package/dist/core/__tests__/{serial → integration}/human-deliver-e2e.test.js +1 -1
  83. package/dist/core/__tests__/{live-mutation-verbs.test.js → integration/live-mutation-verbs.test.js} +22 -33
  84. package/dist/core/__tests__/{serial → integration}/live-mutation.test.js +21 -41
  85. package/dist/core/__tests__/integration/refresh-stall-recycle.test.d.ts +1 -0
  86. package/dist/core/__tests__/{serial → integration}/refresh-stall-recycle.test.js +1 -1
  87. package/dist/core/__tests__/integration/revive.test.d.ts +1 -0
  88. package/dist/core/__tests__/{serial → integration}/revive.test.js +38 -19
  89. package/dist/core/__tests__/integration/spawn-root.test.d.ts +1 -0
  90. package/dist/core/__tests__/{serial → integration}/spawn-root.test.js +104 -1
  91. package/dist/core/__tests__/integration/subscription-delivery.test.d.ts +1 -0
  92. package/dist/core/__tests__/{serial → integration}/subscription-delivery.test.js +1 -1
  93. package/dist/core/__tests__/integration/tmux-surface.test.d.ts +1 -0
  94. package/dist/core/__tests__/{serial → integration}/tmux-surface.test.js +1 -1
  95. package/dist/core/__tests__/integration/worktree-land.test.d.ts +1 -0
  96. package/dist/core/__tests__/integration/worktree-land.test.js +400 -0
  97. package/dist/core/__tests__/integration/worktree-reap.test.d.ts +1 -0
  98. package/dist/core/__tests__/{serial/worktree.test.js → integration/worktree-reap.test.js} +6 -338
  99. package/dist/core/__tests__/kickoff.test.js +16 -5
  100. package/dist/core/__tests__/memory-resolver-precedence.test.js +122 -91
  101. package/dist/core/__tests__/nested-store-discovery.test.js +5 -3
  102. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
  103. package/dist/core/__tests__/on-read-dedup-resume.test.js +39 -27
  104. package/dist/core/__tests__/on-read-nested-store.test.js +19 -13
  105. package/dist/core/__tests__/profile-project-memory-delivery.test.js +138 -44
  106. package/dist/core/__tests__/repository-association.test.d.ts +1 -0
  107. package/dist/core/__tests__/repository-association.test.js +153 -0
  108. package/dist/core/__tests__/repository-root-identity.test.d.ts +1 -0
  109. package/dist/core/__tests__/repository-root-identity.test.js +219 -0
  110. package/dist/core/__tests__/review-model-floor.test.js +12 -4
  111. package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.js +27 -11
  112. package/dist/core/__tests__/warm-claim-preference-snapshot.test.d.ts +1 -0
  113. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +40 -0
  114. package/dist/core/canvas/canvas.d.ts +3 -0
  115. package/dist/core/canvas/canvas.js +30 -10
  116. package/dist/core/canvas/db.js +28 -1
  117. package/dist/core/canvas/paths.d.ts +4 -6
  118. package/dist/core/canvas/paths.js +8 -6
  119. package/dist/core/canvas/render-source.js +2 -2
  120. package/dist/core/canvas/types.d.ts +9 -13
  121. package/dist/core/config.d.ts +3 -3
  122. package/dist/core/config.js +3 -3
  123. package/dist/core/exclusive-lock.d.ts +2 -0
  124. package/dist/core/exclusive-lock.js +21 -0
  125. package/dist/core/git.d.ts +0 -1
  126. package/dist/core/git.js +0 -3
  127. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +1 -0
  128. package/dist/core/human/feedback-companion.js +3 -0
  129. package/dist/core/human/scan.js +8 -1
  130. package/dist/core/keybindings/catalog.d.ts +2 -2
  131. package/dist/core/keybindings/catalog.js +2 -1
  132. package/dist/core/memory/doc-link-grammar.js +2 -2
  133. package/dist/core/memory/history.d.ts +24 -0
  134. package/dist/core/memory/history.js +66 -1
  135. package/dist/core/memory/identity.d.ts +65 -0
  136. package/dist/core/memory/identity.js +185 -0
  137. package/dist/core/memory/inline-ref-guidance.d.ts +1 -1
  138. package/dist/core/memory/inline-ref-guidance.js +1 -1
  139. package/dist/core/memory/inline-ref-inventory.d.ts +3 -10
  140. package/dist/core/memory/inline-ref-inventory.js +30 -62
  141. package/dist/core/memory/lint.d.ts +129 -0
  142. package/dist/core/memory/lint.js +517 -0
  143. package/dist/core/memory/project-namespace.d.ts +31 -0
  144. package/dist/core/memory/project-namespace.js +85 -0
  145. package/dist/core/memory/repository-association.d.ts +31 -0
  146. package/dist/core/memory/repository-association.js +129 -0
  147. package/dist/core/memory/tree.d.ts +39 -0
  148. package/dist/core/memory/tree.js +93 -0
  149. package/dist/core/memory-resolver.d.ts +193 -90
  150. package/dist/core/memory-resolver.js +461 -375
  151. package/dist/core/nested-stores.js +6 -13
  152. package/dist/core/profiles/select.d.ts +4 -1
  153. package/dist/core/profiles/select.js +108 -48
  154. package/dist/core/review/__tests__/capture-origin.test.js +2 -2
  155. package/dist/core/review/__tests__/stage-identity.test.js +2 -2
  156. package/dist/core/review/companion.js +11 -2
  157. package/dist/core/runtime/bearings.d.ts +2 -2
  158. package/dist/core/runtime/bearings.js +3 -3
  159. package/dist/core/runtime/broker/daemon-ops.d.ts +2 -2
  160. package/dist/core/runtime/broker/rebind.js +5 -0
  161. package/dist/core/runtime/broker-extension-render.d.ts +7 -3
  162. package/dist/core/runtime/broker-extension-render.js +10 -5
  163. package/dist/core/runtime/broker-persona-guidance.d.ts +19 -5
  164. package/dist/core/runtime/broker-persona-guidance.js +122 -27
  165. package/dist/core/runtime/deliver-live.d.ts +16 -4
  166. package/dist/core/runtime/deliver-live.js +29 -15
  167. package/dist/core/runtime/kickoff.d.ts +3 -3
  168. package/dist/core/runtime/kickoff.js +8 -16
  169. package/dist/core/runtime/launch.js +1 -1
  170. package/dist/core/runtime/lifecycle.js +2 -3
  171. package/dist/core/runtime/nodes.d.ts +3 -4
  172. package/dist/core/runtime/nodes.js +3 -4
  173. package/dist/core/runtime/persona.d.ts +8 -12
  174. package/dist/core/runtime/persona.js +24 -96
  175. package/dist/core/runtime/promote.d.ts +2 -2
  176. package/dist/core/runtime/promote.js +8 -21
  177. package/dist/core/runtime/revive.js +20 -17
  178. package/dist/core/runtime/spawn.js +18 -7
  179. package/dist/core/runtime/tmux-bindings.js +2 -3
  180. package/dist/core/runtime/warm-pool.js +3 -4
  181. package/dist/core/scope.js +2 -0
  182. package/dist/core/self-update.d.ts +0 -2
  183. package/dist/core/self-update.js +2 -35
  184. package/dist/core/substrate/__tests__/surface-match-memory-read.test.d.ts +1 -0
  185. package/dist/core/substrate/__tests__/surface-match-memory-read.test.js +28 -0
  186. package/dist/core/substrate/index.d.ts +2 -2
  187. package/dist/core/substrate/index.js +1 -1
  188. package/dist/core/substrate/injected-store.d.ts +43 -27
  189. package/dist/core/substrate/injected-store.js +208 -104
  190. package/dist/core/substrate/listings.d.ts +19 -12
  191. package/dist/core/substrate/listings.js +75 -52
  192. package/dist/core/substrate/on-read-node.d.ts +4 -7
  193. package/dist/core/substrate/on-read-node.js +6 -8
  194. package/dist/core/substrate/on-read.d.ts +22 -25
  195. package/dist/core/substrate/on-read.js +103 -147
  196. package/dist/core/substrate/render-node.d.ts +4 -7
  197. package/dist/core/substrate/render-node.js +5 -7
  198. package/dist/core/substrate/render.d.ts +21 -3
  199. package/dist/core/substrate/render.js +291 -223
  200. package/dist/core/substrate/schema.d.ts +1 -13
  201. package/dist/core/substrate/schema.js +5 -40
  202. package/dist/core/substrate/session-cache.d.ts +14 -4
  203. package/dist/core/substrate/session-cache.js +40 -22
  204. package/dist/core/substrate/surface-match.d.ts +9 -7
  205. package/dist/core/substrate/surface-match.js +26 -25
  206. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +30 -0
  207. package/dist/daemon/__tests__/helpers/source-daemon.js +174 -0
  208. package/dist/daemon/__tests__/integration/migration-startup.test.d.ts +1 -0
  209. package/dist/daemon/__tests__/integration/migration-startup.test.js +97 -0
  210. package/dist/daemon/api/__tests__/bridge-heartbeat.test.js +21 -5
  211. package/dist/daemon/api/handlers/broker-ops.js +21 -16
  212. package/dist/daemon/api/handlers/memory.js +2 -0
  213. package/dist/daemon/crtrd.js +2 -0
  214. package/dist/daemon/human/finish.js +8 -1
  215. package/dist/daemon/manage.d.ts +0 -1
  216. package/dist/daemon/manage.js +7 -16
  217. package/dist/daemon/startup-policy.d.ts +1 -0
  218. package/dist/daemon/startup-policy.js +1 -0
  219. package/dist/migrations/001-surfaces-frontmatter.js +21 -109
  220. package/dist/migrations/002-profile-project-memory.js +1 -0
  221. package/dist/migrations/003-repository-root-memory-identity/front-door.d.ts +26 -0
  222. package/dist/migrations/003-repository-root-memory-identity/front-door.js +231 -0
  223. package/dist/migrations/003-repository-root-memory-identity/index.d.ts +2 -0
  224. package/dist/migrations/003-repository-root-memory-identity/index.js +513 -0
  225. package/dist/migrations/003-repository-root-memory-identity/references.d.ts +95 -0
  226. package/dist/migrations/003-repository-root-memory-identity/references.js +469 -0
  227. package/dist/migrations/003-repository-root-memory-identity/repository-facts.d.ts +39 -0
  228. package/dist/migrations/003-repository-root-memory-identity/repository-facts.js +349 -0
  229. package/dist/migrations/__tests__/activation-concurrency.test.d.ts +1 -0
  230. package/dist/migrations/__tests__/activation-concurrency.test.js +145 -0
  231. package/dist/migrations/__tests__/activation.test.d.ts +1 -0
  232. package/dist/migrations/__tests__/activation.test.js +149 -0
  233. package/dist/migrations/__tests__/deletion-and-root-declaration.test.d.ts +1 -0
  234. package/dist/migrations/__tests__/deletion-and-root-declaration.test.js +149 -0
  235. package/dist/migrations/activation.d.ts +16 -0
  236. package/dist/migrations/activation.js +78 -0
  237. package/dist/migrations/convergent.d.ts +14 -3
  238. package/dist/migrations/convergent.js +21 -10
  239. package/dist/migrations/corpus.d.ts +78 -0
  240. package/dist/migrations/corpus.js +497 -0
  241. package/dist/migrations/frontmatter-splice.d.ts +15 -0
  242. package/dist/migrations/frontmatter-splice.js +176 -0
  243. package/dist/migrations/registry.d.ts +6 -1
  244. package/dist/migrations/registry.js +7 -2
  245. package/dist/migrations/runner.d.ts +41 -0
  246. package/dist/migrations/runner.js +81 -0
  247. package/dist/migrations/types.d.ts +148 -9
  248. package/dist/migrations/types.js +9 -2
  249. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +225 -17
  250. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +11 -3
  251. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -5
  252. package/dist/pi-extensions/canvas-context-intro.js +50 -46
  253. package/dist/pi-extensions/canvas-doc-substrate.d.ts +1 -8
  254. package/dist/pi-extensions/canvas-doc-substrate.js +55 -122
  255. package/dist/pi-extensions/canvas-stophook.js +6 -13
  256. package/dist/shared/generated-context.d.ts +0 -3
  257. package/dist/shared/generated-context.js +0 -57
  258. package/dist/shared/tool-groups.js +2 -3
  259. package/dist/types.d.ts +8 -11
  260. package/dist/types.js +4 -31
  261. package/package.json +5 -4
  262. package/runtime.lock.json +2 -2
  263. package/dist/builtin-memory/05-kinds/design/00-base.md +0 -17
  264. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +0 -15
  265. package/dist/builtin-memory/05-kinds/design/design-contract.md +0 -19
  266. package/dist/builtin-memory/05-kinds/developer/00-base.md +0 -17
  267. package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +0 -15
  268. package/dist/builtin-memory/05-kinds/plan/00-base.md +0 -17
  269. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +0 -17
  270. package/dist/builtin-memory/05-kinds/plan/plan-contract.md +0 -28
  271. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -15
  272. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -15
  273. package/dist/builtin-memory/05-kinds/plan/reviewers/lens-contract.md +0 -13
  274. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -17
  275. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +0 -17
  276. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -17
  277. package/dist/builtin-memory/05-kinds/spec/00-base.md +0 -17
  278. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +0 -15
  279. package/dist/builtin-memory/05-kinds/spec/requirements.md +0 -15
  280. package/dist/builtin-memory/design/guide.md +0 -35
  281. package/dist/builtin-memory/design/roadmap.md +0 -21
  282. package/dist/builtin-memory/development.md +0 -113
  283. package/dist/builtin-memory/plan/roadmap.md +0 -25
  284. package/dist/builtin-memory/spec/guide.md +0 -53
  285. package/dist/builtin-memory/spec/requirements.md +0 -29
  286. package/dist/builtin-memory/spec/roadmap.md +0 -36
  287. package/dist/builtin-memory/testing.md +0 -39
  288. /package/dist/api/__tests__/{serial → integration}/client.test.d.ts +0 -0
  289. /package/dist/api/__tests__/{serial → integration}/client.test.js +0 -0
  290. /package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{serial → integration}/provider-rotation.test.ts +0 -0
  291. /package/dist/clients/{inbox/__tests__/serial/inbox-controller.test.d.ts → attach/__tests__/pane-tag-successor.test.d.ts} +0 -0
  292. /package/dist/clients/{inbox/__tests__/serial/mount-panel.test.d.ts → attach/__tests__/profile-files.test.d.ts} +0 -0
  293. /package/dist/{core/__tests__/live-mutation-verbs.test.d.ts → clients/inbox/__tests__/integration/inbox-controller.test.d.ts} +0 -0
  294. /package/dist/clients/inbox/__tests__/{serial → integration}/inbox-controller.test.js +0 -0
  295. /package/dist/{core/__tests__/serial/broker-fork-seam.test.d.ts → clients/inbox/__tests__/integration/mount-panel.test.d.ts} +0 -0
  296. /package/dist/clients/inbox/__tests__/{serial → integration}/mount-panel.test.js +0 -0
  297. /package/dist/{core/__tests__/serial/broker-sdk-wiring.test.d.ts → commands/__tests__/surface-reload-target.test.d.ts} +0 -0
  298. /package/dist/{core/__tests__/serial/broker-snapshot-history.test.d.ts → commands/memory/__tests__/command-selector-and-mutation-guards.test.d.ts} +0 -0
  299. /package/dist/{core/__tests__/serial/command-plugins.test.d.ts → commands/memory/__tests__/repository-root-lint.test.d.ts} +0 -0
  300. /package/dist/{core/__tests__/serial/deferred-no-wake.test.d.ts → commands/sys/__tests__/sync-project-guidance.test.d.ts} +0 -0
  301. /package/dist/core/__tests__/{serial/flagship-lifecycle.test.d.ts → config-change-delta.test.d.ts} +0 -0
  302. /package/dist/core/__tests__/{serial/host-teardown-process-group.test.d.ts → integration/broker-fork-seam.test.d.ts} +0 -0
  303. /package/dist/core/__tests__/{serial/human-deliver-e2e.test.d.ts → integration/broker-sdk-wiring.test.d.ts} +0 -0
  304. /package/dist/core/__tests__/{serial/live-mutation.test.d.ts → integration/broker-snapshot-history.test.d.ts} +0 -0
  305. /package/dist/core/__tests__/{serial/refresh-stall-recycle.test.d.ts → integration/command-plugins.test.d.ts} +0 -0
  306. /package/dist/core/__tests__/{serial/revive.test.d.ts → integration/deferred-no-wake.test.d.ts} +0 -0
  307. /package/dist/core/__tests__/{serial/spawn-root.test.d.ts → integration/flagship-lifecycle.test.d.ts} +0 -0
  308. /package/dist/core/__tests__/{serial/subscription-delivery.test.d.ts → integration/host-teardown-process-group.test.d.ts} +0 -0
  309. /package/dist/core/__tests__/{serial/tmux-surface.test.d.ts → integration/human-deliver-e2e.test.d.ts} +0 -0
  310. /package/dist/core/__tests__/{serial/worktree.test.d.ts → integration/live-mutation-verbs.test.d.ts} +0 -0
  311. /package/dist/core/{human/__tests__/serial/inbox-core.test.d.ts → __tests__/integration/live-mutation.test.d.ts} +0 -0
  312. /package/dist/core/human/__tests__/{serial → integration}/inbox-core.test.js +0 -0
@@ -0,0 +1,149 @@
1
+ import assert from 'node:assert/strict';
2
+ import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import test from 'node:test';
6
+ import { runConvergentMigrations } from '../convergent.js';
7
+ import { runCorpusMigrations } from '../corpus.js';
8
+ function inTemp(run) {
9
+ const root = mkdtempSync(join(tmpdir(), 'crtr-migration-deletion-'));
10
+ try {
11
+ run(root);
12
+ }
13
+ finally {
14
+ rmSync(root, { recursive: true, force: true });
15
+ }
16
+ }
17
+ function plan(overrides = {}) {
18
+ return {
19
+ blockers: [],
20
+ consumers: [],
21
+ identities: [],
22
+ repositories: [],
23
+ storePrefixes: [],
24
+ renames: [],
25
+ references: [],
26
+ ...overrides,
27
+ };
28
+ }
29
+ function corpus(storeRoot, docs) {
30
+ return {
31
+ stores: [{
32
+ key: storeRoot,
33
+ descriptor: { scope: 'project', storeRoot, namespace: '', mountStatus: 'ready', projectMemory: 'memory' },
34
+ snapshot: { root: storeRoot, docs },
35
+ discovery: [],
36
+ targets: [],
37
+ writable: true,
38
+ }],
39
+ targets: [],
40
+ roots: [],
41
+ store: () => undefined,
42
+ storesForTarget: () => [],
43
+ };
44
+ }
45
+ function doc(path, relPath, source) {
46
+ return { path, relPath, source, frontmatter: null, body: source };
47
+ }
48
+ test('convergent deletion folds dry runs without writing, writes real deletions, and skips absent paths', () => {
49
+ inTemp((root) => {
50
+ const target = join(root, 'obsolete.md');
51
+ const absent = join(root, 'already-gone.md');
52
+ writeFileSync(target, '# obsolete\n');
53
+ const migration = {
54
+ id: 'delete',
55
+ lane: 'convergent',
56
+ description: 'delete obsolete docs',
57
+ apply: () => [{ path: target, after: null }, { path: absent, after: null }],
58
+ };
59
+ const dry = runConvergentMigrations(root, { dryRun: true, migrations: [migration] });
60
+ assert.deepEqual(dry.applied, [{ migration: migration.description, files: [target] }]);
61
+ assert.deepEqual(dry.snapshot.docs, []);
62
+ assert.equal(existsSync(target), true);
63
+ const wrote = runConvergentMigrations(root, { migrations: [migration] });
64
+ assert.deepEqual(wrote.applied, [{ migration: migration.description, files: [target] }]);
65
+ assert.equal(existsSync(target), false);
66
+ });
67
+ });
68
+ test('corpus deletion folds before later migration plans and leaves dry-run disk bytes untouched', () => {
69
+ inTemp((root) => {
70
+ const storeRoot = join(root, 'child', '.crouter', 'memory');
71
+ const target = join(storeRoot, 'obsolete.md');
72
+ mkdirSync(storeRoot, { recursive: true });
73
+ writeFileSync(target, '# obsolete\n');
74
+ let laterSaw;
75
+ const deletion = {
76
+ id: 'delete',
77
+ lane: 'corpus',
78
+ description: 'delete obsolete docs',
79
+ plan: () => plan({ identities: [{ path: target, after: null }] }),
80
+ };
81
+ const observer = {
82
+ id: 'observe',
83
+ lane: 'corpus',
84
+ description: 'observe folded deletion',
85
+ plan: (working) => {
86
+ laterSaw = working.stores[0]?.snapshot.docs.length;
87
+ return plan();
88
+ },
89
+ };
90
+ const input = corpus(storeRoot, [doc(target, 'obsolete.md', '# obsolete\n')]);
91
+ const dry = runCorpusMigrations(input, { dryRun: true, migrations: [deletion, observer] });
92
+ assert.equal(laterSaw, 0);
93
+ assert.deepEqual(dry.wrote.identities, [target]);
94
+ assert.equal(readFileSync(target, 'utf8'), '# obsolete\n');
95
+ runCorpusMigrations(input, { migrations: [deletion] });
96
+ assert.equal(existsSync(target), false);
97
+ });
98
+ });
99
+ test('corpus permits a plan-authorized repository-root declaration outside discovered stores', () => {
100
+ inTemp((repositoryRoot) => {
101
+ const descendantStore = join(repositoryRoot, 'packages', 'tool', '.crouter', 'memory');
102
+ const declarationPath = join(repositoryRoot, '.crouter', 'memory', 'INDEX.md');
103
+ mkdirSync(descendantStore, { recursive: true });
104
+ const migration = {
105
+ id: 'create-root-declaration',
106
+ lane: 'corpus',
107
+ description: 'create root declaration',
108
+ plan: () => plan({
109
+ identities: [{ path: declarationPath, after: '# root declaration\n' }],
110
+ repositories: [{
111
+ repositoryRoot,
112
+ repositoryKey: 'repository',
113
+ declarationPath,
114
+ namespace: 'repository',
115
+ source: 'declared',
116
+ action: 'created',
117
+ }],
118
+ }),
119
+ };
120
+ runCorpusMigrations(corpus(descendantStore, []), { migrations: [migration] });
121
+ assert.equal(readFileSync(declarationPath, 'utf8'), '# root declaration\n');
122
+ });
123
+ });
124
+ test('corpus rejects every outside-store path other than the plan declaration path', () => {
125
+ inTemp((repositoryRoot) => {
126
+ const descendantStore = join(repositoryRoot, 'packages', 'tool', '.crouter', 'memory');
127
+ const declarationPath = join(repositoryRoot, '.crouter', 'memory', 'INDEX.md');
128
+ const otherPath = join(repositoryRoot, '.crouter', 'memory', 'other.md');
129
+ mkdirSync(descendantStore, { recursive: true });
130
+ const migration = {
131
+ id: 'reject-other-outside-path',
132
+ lane: 'corpus',
133
+ description: 'reject other outside path',
134
+ plan: () => plan({
135
+ identities: [{ path: otherPath, after: '# not authorized\n' }],
136
+ repositories: [{
137
+ repositoryRoot,
138
+ repositoryKey: 'repository',
139
+ declarationPath,
140
+ namespace: 'repository',
141
+ source: 'declared',
142
+ action: 'created',
143
+ }],
144
+ }),
145
+ };
146
+ assert.throws(() => runCorpusMigrations(corpus(descendantStore, []), { migrations: [migration] }), new RegExp(`outside every discovered store: ${otherPath}`));
147
+ assert.equal(existsSync(otherPath), false);
148
+ });
149
+ });
@@ -0,0 +1,16 @@
1
+ import { runOnDiskMigrations, type OnDiskMigrationRunResult } from './runner.js';
2
+ export type OnDiskMigrationRunner = typeof runOnDiskMigrations;
3
+ interface CoordinationOptions {
4
+ timeoutMs?: number;
5
+ runner?: OnDiskMigrationRunner;
6
+ }
7
+ export interface ForcedMigrationOptions extends CoordinationOptions {
8
+ dryRun?: boolean;
9
+ explicitDirs?: readonly string[];
10
+ }
11
+ /** Run startup migration only when this home lacks the current completion marker. */
12
+ export declare function activateOnDiskMigrations(options?: CoordinationOptions): Promise<OnDiskMigrationRunResult | null>;
13
+ export declare function ensureOnDiskMigrations(): Promise<void>;
14
+ /** Run migrations regardless of the marker; dry runs leave marker state untouched. */
15
+ export declare function runForcedOnDiskMigrations(options: ForcedMigrationOptions): Promise<OnDiskMigrationRunResult>;
16
+ export {};
@@ -0,0 +1,78 @@
1
+ import { mkdirSync, rmSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ import { onDiskMigrationLockPath, onDiskMigrationMarkerPath } from '../core/canvas/paths.js';
4
+ import { withExclusiveDirectoryLockAsync } from '../core/exclusive-lock.js';
5
+ import { DAEMON_STARTUP_WINDOW_MS } from '../daemon/startup-policy.js';
6
+ import { atomicWriteJson, readJsonOrNull } from '../core/fs-utils.js';
7
+ import { onDiskMigrationIdentity } from './registry.js';
8
+ import { runOnDiskMigrations } from './runner.js';
9
+ function markerIsCurrent() {
10
+ const stored = readJsonOrNull(onDiskMigrationMarkerPath());
11
+ return JSON.stringify(stored) === JSON.stringify(onDiskMigrationIdentity());
12
+ }
13
+ function writeCurrentMarker() {
14
+ atomicWriteJson(onDiskMigrationMarkerPath(), onDiskMigrationIdentity());
15
+ }
16
+ function blockerPaths(result) {
17
+ return [...new Set(result.blockers.flatMap((blocker) => [
18
+ ...(blocker.path === undefined ? [] : [blocker.path]),
19
+ ...(blocker.paths ?? []),
20
+ ...(blocker.storeRoot === undefined ? [] : [blocker.storeRoot]),
21
+ ]))];
22
+ }
23
+ function activationError(result) {
24
+ const paths = blockerPaths(result);
25
+ const findings = result.blockers.map((blocker) => `${blocker.kind}: ${blocker.message}`);
26
+ const writes = [
27
+ ...result.wrote.profileManifests,
28
+ ...result.wrote.documents,
29
+ ...result.wrote.corpusConsumers,
30
+ ...result.wrote.corpusIdentities,
31
+ ];
32
+ const lines = result.blockers.length > 0
33
+ ? [`on-disk migration blocked by ${result.blockers.length} finding(s)`, ...findings]
34
+ : ['on-disk migration did not complete final verification'];
35
+ if (paths.length > 0)
36
+ lines.push(`Blocker paths: ${paths.join(', ')}`);
37
+ if (writes.length > 0)
38
+ lines.push(`Writes completed before failure: ${writes.join(', ')}`);
39
+ lines.push('Repair: crtr sys migrate');
40
+ return new Error(lines.join('\n'));
41
+ }
42
+ async function coordinate(mode, options) {
43
+ const lockPath = onDiskMigrationLockPath();
44
+ mkdirSync(dirname(lockPath), { recursive: true, mode: 0o700 });
45
+ return withExclusiveDirectoryLockAsync(lockPath, async () => {
46
+ if (mode === 'activation' && markerIsCurrent())
47
+ return null;
48
+ const dryRun = options.dryRun === true;
49
+ if (!dryRun)
50
+ rmSync(onDiskMigrationMarkerPath(), { force: true });
51
+ const result = await (options.runner ?? runOnDiskMigrations)({
52
+ dryRun,
53
+ explicitDirs: options.explicitDirs,
54
+ });
55
+ if (!dryRun && result.finalVerificationSucceeded)
56
+ writeCurrentMarker();
57
+ if (mode === 'activation' && !result.finalVerificationSucceeded)
58
+ throw activationError(result);
59
+ return result;
60
+ }, {
61
+ timeoutMs: options.timeoutMs ?? DAEMON_STARTUP_WINDOW_MS,
62
+ timeoutError: () => new Error(`timed out waiting for on-disk migration lock: ${lockPath}`),
63
+ });
64
+ }
65
+ /** Run startup migration only when this home lacks the current completion marker. */
66
+ export async function activateOnDiskMigrations(options = {}) {
67
+ return coordinate('activation', options);
68
+ }
69
+ export async function ensureOnDiskMigrations() {
70
+ await activateOnDiskMigrations();
71
+ }
72
+ /** Run migrations regardless of the marker; dry runs leave marker state untouched. */
73
+ export async function runForcedOnDiskMigrations(options) {
74
+ const result = await coordinate('forced', options);
75
+ if (result === null)
76
+ throw new Error('forced on-disk migration unexpectedly skipped');
77
+ return result;
78
+ }
@@ -1,4 +1,4 @@
1
- import type { ConvergentMigrationContext, StateMigration, StoreSnapshot } from './types.js';
1
+ import type { DocChange, StateMigration, StoreSnapshot } from './types.js';
2
2
  /** A doc excluded from the snapshot because its frontmatter is not valid YAML.
3
3
  * Per-doc throw isolation at the collection layer: the bad file is named and
4
4
  * the rest of the store still migrates. */
@@ -14,13 +14,25 @@ export interface ConvergentRunResult {
14
14
  files: string[];
15
15
  }[];
16
16
  skipped: SkippedDoc[];
17
+ /** The store's docs with every planned change folded in — the bytes on disk
18
+ * after a write run, and the bytes a write run WOULD have produced under
19
+ * `--dry-run`. What the corpus lane plans against. */
20
+ snapshot: StoreSnapshot;
17
21
  }
18
22
  /** Snapshot every parseable `.md` under `root` (hidden dirs — `.history`
19
- * sidecars and the like — skipped, mirroring substrate doc enumeration). */
23
+ * sidecars and the like — skipped, mirroring substrate doc enumeration).
24
+ * `SKILL.md` bundles are Agent Skills, not memory docs: they carry no
25
+ * canonical identity and are never rewritten. */
20
26
  export declare function loadStoreSnapshot(root: string): {
21
27
  snapshot: StoreSnapshot;
22
28
  skipped: SkippedDoc[];
23
29
  };
30
+ /** Fold one applied change back into the in-memory snapshot so the NEXT
31
+ * migration plans against post-change state (dry runs included — that is what
32
+ * makes a dry-run diff equal the real run's writes). A migration that emits
33
+ * invalid YAML is a defect and throws here, before anything else compounds
34
+ * on its output. */
35
+ export declare function foldDocChange(snapshot: StoreSnapshot, change: DocChange): void;
24
36
  /** Run every registered convergent migration over the store at `root`, in
25
37
  * registry order. No-op changes (identical text) are filtered; each real
26
38
  * change is written atomically unless `dryRun`. Journaled migrations in the
@@ -28,5 +40,4 @@ export declare function loadStoreSnapshot(root: string): {
28
40
  export declare function runConvergentMigrations(root: string, opts?: {
29
41
  dryRun?: boolean;
30
42
  migrations?: readonly StateMigration[];
31
- context?: ConvergentMigrationContext;
32
43
  }): ConvergentRunResult;
@@ -4,7 +4,7 @@
4
4
  // whatever still matches an old shape, so a doc that arrives later (sync,
5
5
  // restore, hand-edit) is caught by the next run.
6
6
  import { relative, sep } from 'node:path';
7
- import { atomicWriteText, readText, walkFiles } from '../core/fs-utils.js';
7
+ import { atomicWriteText, readText, removePath, walkFiles } from '../core/fs-utils.js';
8
8
  import { parseFrontmatterGeneric } from '../core/frontmatter.js';
9
9
  import { STATE_MIGRATIONS } from './registry.js';
10
10
  function parseDoc(root, file) {
@@ -19,11 +19,13 @@ function parseDoc(root, file) {
19
19
  }
20
20
  }
21
21
  /** Snapshot every parseable `.md` under `root` (hidden dirs — `.history`
22
- * sidecars and the like — skipped, mirroring substrate doc enumeration). */
22
+ * sidecars and the like — skipped, mirroring substrate doc enumeration).
23
+ * `SKILL.md` bundles are Agent Skills, not memory docs: they carry no
24
+ * canonical identity and are never rewritten. */
23
25
  export function loadStoreSnapshot(root) {
24
26
  const docs = [];
25
27
  const skipped = [];
26
- for (const file of walkFiles(root, (n) => n.endsWith('.md'), (d) => d.startsWith('.'))) {
28
+ for (const file of walkFiles(root, (n) => n.endsWith('.md') && n !== 'SKILL.md', (d) => d.startsWith('.'))) {
27
29
  const parsed = parseDoc(root, file);
28
30
  if ('doc' in parsed)
29
31
  docs.push(parsed.doc);
@@ -37,11 +39,16 @@ export function loadStoreSnapshot(root) {
37
39
  * makes a dry-run diff equal the real run's writes). A migration that emits
38
40
  * invalid YAML is a defect and throws here, before anything else compounds
39
41
  * on its output. */
40
- function refreshDoc(snapshot, change) {
42
+ export function foldDocChange(snapshot, change) {
43
+ const i = snapshot.docs.findIndex((d) => d.path === change.path);
44
+ if (change.after === null) {
45
+ if (i >= 0)
46
+ snapshot.docs.splice(i, 1);
47
+ return;
48
+ }
41
49
  const relPath = relative(snapshot.root, change.path).split(sep).join('/');
42
50
  const { data, body } = parseFrontmatterGeneric(change.after);
43
51
  const doc = { path: change.path, relPath, source: change.after, frontmatter: data, body };
44
- const i = snapshot.docs.findIndex((d) => d.path === change.path);
45
52
  if (i >= 0)
46
53
  snapshot.docs[i] = doc;
47
54
  else
@@ -57,15 +64,19 @@ export function runConvergentMigrations(root, opts = {}) {
57
64
  const applied = [];
58
65
  for (const migration of migrations) {
59
66
  const bySource = new Map(snapshot.docs.map((d) => [d.path, d.source]));
60
- const changes = migration.apply(snapshot, opts.context).filter((c) => bySource.get(c.path) !== c.after);
67
+ const changes = migration.apply(snapshot).filter((change) => change.after === null ? bySource.has(change.path) : bySource.get(change.path) !== change.after);
61
68
  if (changes.length === 0)
62
69
  continue;
63
70
  for (const change of changes) {
64
- if (opts.dryRun !== true)
65
- atomicWriteText(change.path, change.after);
66
- refreshDoc(snapshot, change);
71
+ if (opts.dryRun !== true) {
72
+ if (change.after === null)
73
+ removePath(change.path);
74
+ else
75
+ atomicWriteText(change.path, change.after);
76
+ }
77
+ foldDocChange(snapshot, change);
67
78
  }
68
79
  applied.push({ migration: migration.description, files: changes.map((c) => c.path) });
69
80
  }
70
- return { root, applied, skipped };
81
+ return { root, applied, skipped, snapshot };
71
82
  }
@@ -0,0 +1,78 @@
1
+ import type { CorpusBlocker, CorpusDiscoveryRoot, CorpusIdentityRename, CorpusReferenceRewrite, CorpusRepositoryDecision, CorpusSnapshot, CorpusStore, CorpusStorePrefix, CorpusTarget, ProfileManifestSnapshot, StateMigration, StoreSnapshot } from './types.js';
2
+ /** A store before its documents are read. */
3
+ export type DiscoveredStore = Omit<CorpusStore, 'snapshot'>;
4
+ export interface CorpusDiscovery {
5
+ /** Every place discovery looked, in the order it looked. */
6
+ roots: CorpusDiscoveryRoot[];
7
+ /** Deduped by realpath, in discovery order. Stores whose directory does not
8
+ * exist are absent: there is nothing to migrate and nothing to point at. */
9
+ stores: DiscoveredStore[];
10
+ targets: CorpusTarget[];
11
+ /** Roots and targets discovery could not read. */
12
+ blockers: CorpusBlocker[];
13
+ nodeMetadata: {
14
+ available: boolean;
15
+ nodes: number;
16
+ error?: string;
17
+ };
18
+ }
19
+ export interface CorpusSkippedDoc {
20
+ storeRoot: string;
21
+ relPath: string;
22
+ error: string;
23
+ }
24
+ export interface CorpusRunResult {
25
+ /** Corpus migrations in the registry. Zero means the lane is inert. */
26
+ migrations: number;
27
+ /** True when blockers exist and a corpus migration was registered to gate. */
28
+ blocked: boolean;
29
+ blockers: CorpusBlocker[];
30
+ planned: {
31
+ migration: string;
32
+ consumers: string[];
33
+ identities: string[];
34
+ }[];
35
+ repositories: CorpusRepositoryDecision[];
36
+ storePrefixes: CorpusStorePrefix[];
37
+ renames: CorpusIdentityRename[];
38
+ references: CorpusReferenceRewrite[];
39
+ /** Files written, or under `--dry-run` the files that would be written. */
40
+ wrote: {
41
+ consumers: string[];
42
+ identities: string[];
43
+ };
44
+ /** True when the post-write rebuild ran every migration's `verify`. */
45
+ verified: boolean;
46
+ }
47
+ /** Discover the whole reachable corpus: every store, the targets that mount
48
+ * them, and the frontier searched to find them. `profiles` are the manifest
49
+ * lane's post-migration snapshots — a pre-migration manifest reads as corrupt,
50
+ * so discovery must run after that lane, not against `listProfiles()`. */
51
+ export declare function discoverCorpus(opts: {
52
+ cwd?: string;
53
+ profiles: readonly ProfileManifestSnapshot[];
54
+ explicitDirs?: readonly string[];
55
+ }): Promise<CorpusDiscovery>;
56
+ /** Read every discovered store's documents. `preloaded` supplies the per-store
57
+ * convergent lane's FOLDED snapshots so the corpus plans against the bytes a
58
+ * write run leaves behind — identical under `--dry-run`, where the same fold
59
+ * ran and nothing was written. */
60
+ export declare function loadCorpusSnapshots(discovery: CorpusDiscovery, opts?: {
61
+ preloaded?: ReadonlyMap<string, StoreSnapshot>;
62
+ }): {
63
+ snapshots: Map<string, StoreSnapshot>;
64
+ skipped: CorpusSkippedDoc[];
65
+ };
66
+ export declare function parseFailureBlockers(skipped: readonly CorpusSkippedDoc[]): CorpusBlocker[];
67
+ export declare function buildCorpusSnapshot(discovery: CorpusDiscovery, snapshots: ReadonlyMap<string, StoreSnapshot>): CorpusSnapshot;
68
+ /** Plan every corpus migration over the whole corpus, then — only when the
69
+ * global plan is blocker-free — write every migration's consumer rewrites
70
+ * before any identity rewrite. `rebuild` re-reads the corpus from file truth
71
+ * for the post-write `verify` pass. */
72
+ export declare function runCorpusMigrations(corpus: CorpusSnapshot, opts?: {
73
+ dryRun?: boolean;
74
+ migrations?: readonly StateMigration[];
75
+ /** Discovery and parse-failure blockers, gating identically to plan ones. */
76
+ blockers?: readonly CorpusBlocker[];
77
+ rebuild?: () => CorpusSnapshot;
78
+ }): CorpusRunResult;