@north-light/crouter 0.3.227 → 0.3.228

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 (286) 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/05-kinds/design/00-base.md +3 -4
  7. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +4 -3
  8. package/dist/builtin-memory/05-kinds/design/design-contract.md +3 -6
  9. package/dist/builtin-memory/05-kinds/plan/00-base.md +3 -4
  10. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +4 -5
  11. package/dist/builtin-memory/05-kinds/plan/plan-contract.md +5 -13
  12. package/dist/builtin-memory/design/guide.md +38 -16
  13. package/dist/builtin-memory/design/roadmap.md +4 -4
  14. package/dist/builtin-memory/insights/init.md +5 -5
  15. package/dist/builtin-memory/internal/INDEX.md +1 -1
  16. package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
  17. package/dist/builtin-memory/internal/memory-loading.md +6 -6
  18. package/dist/builtin-memory/internal/plugins.md +1 -1
  19. package/dist/builtin-memory/plan/guide.md +53 -0
  20. package/dist/builtin-memory/plan/roadmap.md +10 -8
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +50 -37
  22. package/dist/clients/attach/__tests__/pane-tag-successor.test.js +56 -0
  23. package/dist/clients/attach/__tests__/profile-files.test.js +21 -0
  24. package/dist/clients/attach/chrome/inbox-strip.js +11 -7
  25. package/dist/clients/attach/session/pane-tag.d.ts +28 -2
  26. package/dist/clients/attach/session/pane-tag.js +48 -22
  27. package/dist/clients/attach/session/profile-files.d.ts +6 -0
  28. package/dist/clients/attach/session/profile-files.js +44 -11
  29. package/dist/clients/attach/slash/dispatch.js +4 -7
  30. package/dist/clients/attach/viewer.js +588 -596
  31. package/dist/commands/__tests__/surface-reload-target.test.js +21 -0
  32. package/dist/commands/api-client.d.ts +3 -7
  33. package/dist/commands/api-client.js +7 -12
  34. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +292 -0
  35. package/dist/commands/memory/__tests__/repository-root-lint.test.js +146 -0
  36. package/dist/commands/memory/delete.js +51 -24
  37. package/dist/commands/memory/edit.js +50 -10
  38. package/dist/commands/memory/find.js +105 -56
  39. package/dist/commands/memory/history.js +51 -31
  40. package/dist/commands/memory/lint.d.ts +0 -9
  41. package/dist/commands/memory/lint.js +78 -322
  42. package/dist/commands/memory/list.d.ts +12 -4
  43. package/dist/commands/memory/list.js +64 -25
  44. package/dist/commands/memory/move.js +103 -73
  45. package/dist/commands/memory/origin.js +35 -5
  46. package/dist/commands/memory/read.d.ts +4 -0
  47. package/dist/commands/memory/read.js +132 -80
  48. package/dist/commands/memory/shared.d.ts +115 -25
  49. package/dist/commands/memory/shared.js +331 -74
  50. package/dist/commands/memory/write.js +72 -21
  51. package/dist/commands/memory.js +2 -2
  52. package/dist/commands/node/lifecycle.js +2 -2
  53. package/dist/commands/pkg/market-manage.js +25 -24
  54. package/dist/commands/pkg/plugin-manage.d.ts +22 -6
  55. package/dist/commands/pkg/plugin-manage.js +118 -25
  56. package/dist/commands/pkg/shared.d.ts +8 -0
  57. package/dist/commands/pkg/shared.js +23 -20
  58. package/dist/commands/surface-reload.d.ts +5 -0
  59. package/dist/commands/surface-reload.js +9 -1
  60. package/dist/commands/sys/__tests__/migrate.test.js +1140 -22
  61. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +218 -0
  62. package/dist/commands/sys/migrate.js +126 -140
  63. package/dist/commands/sys/panels/profiles-panel.d.ts +66 -0
  64. package/dist/commands/sys/panels/profiles-panel.js +599 -0
  65. package/dist/commands/sys/settings-shell.d.ts +4 -2
  66. package/dist/commands/sys/settings-shell.js +35 -4
  67. package/dist/commands/sys/settings.js +21 -5
  68. package/dist/commands/sys/sync-deps.d.ts +2 -0
  69. package/dist/commands/sys/sync-deps.js +26 -15
  70. package/dist/commands/sys/sync-project-guidance.js +228 -145
  71. package/dist/commands/sys/sync-skills.js +28 -17
  72. package/dist/commands/sys/update.js +11 -3
  73. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +15 -2
  74. package/dist/core/__tests__/config-change-delta.test.js +106 -0
  75. package/dist/core/__tests__/context-intro.test.js +13 -9
  76. package/dist/core/__tests__/daemon-boot.test.js +22 -16
  77. package/dist/core/__tests__/fixtures/memory-slash-live-probe.js +5 -1
  78. package/dist/core/__tests__/human-deliver.test.js +19 -0
  79. package/dist/core/__tests__/inline-memory-refs.test.js +50 -46
  80. package/dist/core/__tests__/{serial → integration}/broker-fork-seam.test.js +1 -1
  81. package/dist/core/__tests__/{serial → integration}/broker-sdk-wiring.test.js +1 -1
  82. package/dist/core/__tests__/{serial → integration}/broker-snapshot-history.test.js +1 -1
  83. package/dist/core/__tests__/{serial → integration}/command-plugins.test.js +94 -3
  84. package/dist/core/__tests__/{serial → integration}/deferred-no-wake.test.js +1 -1
  85. package/dist/core/__tests__/{serial → integration}/flagship-lifecycle.test.js +13 -27
  86. package/dist/core/__tests__/{serial → integration}/host-teardown-process-group.test.js +1 -1
  87. package/dist/core/__tests__/{serial → integration}/human-deliver-e2e.test.js +1 -1
  88. package/dist/core/__tests__/{live-mutation-verbs.test.js → integration/live-mutation-verbs.test.js} +22 -33
  89. package/dist/core/__tests__/{serial → integration}/live-mutation.test.js +21 -41
  90. package/dist/core/__tests__/integration/refresh-stall-recycle.test.d.ts +1 -0
  91. package/dist/core/__tests__/{serial → integration}/refresh-stall-recycle.test.js +1 -1
  92. package/dist/core/__tests__/integration/revive.test.d.ts +1 -0
  93. package/dist/core/__tests__/{serial → integration}/revive.test.js +38 -19
  94. package/dist/core/__tests__/integration/spawn-root.test.d.ts +1 -0
  95. package/dist/core/__tests__/{serial → integration}/spawn-root.test.js +104 -1
  96. package/dist/core/__tests__/integration/subscription-delivery.test.d.ts +1 -0
  97. package/dist/core/__tests__/{serial → integration}/subscription-delivery.test.js +1 -1
  98. package/dist/core/__tests__/integration/tmux-surface.test.d.ts +1 -0
  99. package/dist/core/__tests__/{serial → integration}/tmux-surface.test.js +1 -1
  100. package/dist/core/__tests__/integration/worktree-land.test.d.ts +1 -0
  101. package/dist/core/__tests__/integration/worktree-land.test.js +400 -0
  102. package/dist/core/__tests__/integration/worktree-reap.test.d.ts +1 -0
  103. package/dist/core/__tests__/{serial/worktree.test.js → integration/worktree-reap.test.js} +6 -338
  104. package/dist/core/__tests__/kickoff.test.js +16 -5
  105. package/dist/core/__tests__/memory-resolver-precedence.test.js +122 -91
  106. package/dist/core/__tests__/nested-store-discovery.test.js +5 -3
  107. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
  108. package/dist/core/__tests__/on-read-dedup-resume.test.js +39 -27
  109. package/dist/core/__tests__/on-read-nested-store.test.js +19 -13
  110. package/dist/core/__tests__/profile-project-memory-delivery.test.js +138 -44
  111. package/dist/core/__tests__/repository-association.test.d.ts +1 -0
  112. package/dist/core/__tests__/repository-association.test.js +153 -0
  113. package/dist/core/__tests__/repository-root-identity.test.d.ts +1 -0
  114. package/dist/core/__tests__/repository-root-identity.test.js +219 -0
  115. package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.js +27 -11
  116. package/dist/core/__tests__/warm-claim-preference-snapshot.test.d.ts +1 -0
  117. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +40 -0
  118. package/dist/core/canvas/canvas.d.ts +3 -0
  119. package/dist/core/canvas/canvas.js +30 -10
  120. package/dist/core/canvas/db.js +28 -1
  121. package/dist/core/canvas/paths.d.ts +4 -6
  122. package/dist/core/canvas/paths.js +8 -6
  123. package/dist/core/canvas/render-source.js +2 -2
  124. package/dist/core/canvas/types.d.ts +9 -13
  125. package/dist/core/exclusive-lock.d.ts +2 -0
  126. package/dist/core/exclusive-lock.js +21 -0
  127. package/dist/core/git.d.ts +0 -1
  128. package/dist/core/git.js +0 -3
  129. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +1 -0
  130. package/dist/core/human/feedback-companion.js +3 -0
  131. package/dist/core/human/scan.js +8 -1
  132. package/dist/core/keybindings/catalog.d.ts +2 -2
  133. package/dist/core/keybindings/catalog.js +2 -1
  134. package/dist/core/memory/doc-link-grammar.js +2 -2
  135. package/dist/core/memory/history.d.ts +24 -0
  136. package/dist/core/memory/history.js +66 -1
  137. package/dist/core/memory/identity.d.ts +65 -0
  138. package/dist/core/memory/identity.js +185 -0
  139. package/dist/core/memory/inline-ref-guidance.d.ts +1 -1
  140. package/dist/core/memory/inline-ref-guidance.js +1 -1
  141. package/dist/core/memory/inline-ref-inventory.d.ts +3 -10
  142. package/dist/core/memory/inline-ref-inventory.js +30 -62
  143. package/dist/core/memory/lint.d.ts +129 -0
  144. package/dist/core/memory/lint.js +517 -0
  145. package/dist/core/memory/project-namespace.d.ts +31 -0
  146. package/dist/core/memory/project-namespace.js +85 -0
  147. package/dist/core/memory/repository-association.d.ts +31 -0
  148. package/dist/core/memory/repository-association.js +129 -0
  149. package/dist/core/memory/tree.d.ts +39 -0
  150. package/dist/core/memory/tree.js +93 -0
  151. package/dist/core/memory-resolver.d.ts +193 -90
  152. package/dist/core/memory-resolver.js +461 -375
  153. package/dist/core/nested-stores.js +6 -13
  154. package/dist/core/profiles/select.d.ts +4 -1
  155. package/dist/core/profiles/select.js +108 -48
  156. package/dist/core/review/__tests__/capture-origin.test.js +2 -2
  157. package/dist/core/review/__tests__/stage-identity.test.js +2 -2
  158. package/dist/core/review/companion.js +11 -2
  159. package/dist/core/runtime/bearings.d.ts +2 -2
  160. package/dist/core/runtime/bearings.js +3 -3
  161. package/dist/core/runtime/broker/daemon-ops.d.ts +2 -2
  162. package/dist/core/runtime/broker/rebind.js +5 -0
  163. package/dist/core/runtime/broker-extension-render.d.ts +7 -3
  164. package/dist/core/runtime/broker-extension-render.js +10 -5
  165. package/dist/core/runtime/broker-persona-guidance.d.ts +19 -5
  166. package/dist/core/runtime/broker-persona-guidance.js +122 -27
  167. package/dist/core/runtime/deliver-live.d.ts +16 -4
  168. package/dist/core/runtime/deliver-live.js +29 -15
  169. package/dist/core/runtime/kickoff.d.ts +3 -3
  170. package/dist/core/runtime/kickoff.js +8 -16
  171. package/dist/core/runtime/lifecycle.js +2 -3
  172. package/dist/core/runtime/nodes.d.ts +3 -4
  173. package/dist/core/runtime/nodes.js +3 -4
  174. package/dist/core/runtime/persona.d.ts +8 -12
  175. package/dist/core/runtime/persona.js +24 -96
  176. package/dist/core/runtime/promote.d.ts +2 -2
  177. package/dist/core/runtime/promote.js +8 -21
  178. package/dist/core/runtime/revive.js +20 -17
  179. package/dist/core/runtime/spawn.js +18 -7
  180. package/dist/core/runtime/tmux-bindings.js +2 -3
  181. package/dist/core/runtime/warm-pool.js +3 -4
  182. package/dist/core/scope.js +2 -0
  183. package/dist/core/self-update.d.ts +0 -2
  184. package/dist/core/self-update.js +2 -35
  185. package/dist/core/substrate/__tests__/surface-match-memory-read.test.d.ts +1 -0
  186. package/dist/core/substrate/__tests__/surface-match-memory-read.test.js +28 -0
  187. package/dist/core/substrate/index.d.ts +2 -2
  188. package/dist/core/substrate/index.js +1 -1
  189. package/dist/core/substrate/injected-store.d.ts +43 -27
  190. package/dist/core/substrate/injected-store.js +208 -104
  191. package/dist/core/substrate/listings.d.ts +19 -12
  192. package/dist/core/substrate/listings.js +75 -52
  193. package/dist/core/substrate/on-read-node.d.ts +4 -7
  194. package/dist/core/substrate/on-read-node.js +6 -8
  195. package/dist/core/substrate/on-read.d.ts +22 -25
  196. package/dist/core/substrate/on-read.js +103 -147
  197. package/dist/core/substrate/render-node.d.ts +4 -7
  198. package/dist/core/substrate/render-node.js +5 -7
  199. package/dist/core/substrate/render.d.ts +21 -3
  200. package/dist/core/substrate/render.js +291 -223
  201. package/dist/core/substrate/schema.d.ts +1 -13
  202. package/dist/core/substrate/schema.js +5 -40
  203. package/dist/core/substrate/session-cache.d.ts +14 -4
  204. package/dist/core/substrate/session-cache.js +40 -22
  205. package/dist/core/substrate/surface-match.d.ts +9 -7
  206. package/dist/core/substrate/surface-match.js +26 -25
  207. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +30 -0
  208. package/dist/daemon/__tests__/helpers/source-daemon.js +174 -0
  209. package/dist/daemon/__tests__/integration/migration-startup.test.d.ts +1 -0
  210. package/dist/daemon/__tests__/integration/migration-startup.test.js +97 -0
  211. package/dist/daemon/api/__tests__/bridge-heartbeat.test.js +21 -5
  212. package/dist/daemon/api/handlers/broker-ops.js +21 -16
  213. package/dist/daemon/api/handlers/memory.js +2 -0
  214. package/dist/daemon/crtrd.js +2 -0
  215. package/dist/daemon/human/finish.js +8 -1
  216. package/dist/daemon/manage.d.ts +0 -1
  217. package/dist/daemon/manage.js +7 -16
  218. package/dist/daemon/startup-policy.d.ts +1 -0
  219. package/dist/daemon/startup-policy.js +1 -0
  220. package/dist/migrations/001-surfaces-frontmatter.js +21 -109
  221. package/dist/migrations/002-profile-project-memory.js +1 -0
  222. package/dist/migrations/003-repository-root-memory-identity/front-door.d.ts +26 -0
  223. package/dist/migrations/003-repository-root-memory-identity/front-door.js +231 -0
  224. package/dist/migrations/003-repository-root-memory-identity/index.d.ts +2 -0
  225. package/dist/migrations/003-repository-root-memory-identity/index.js +513 -0
  226. package/dist/migrations/003-repository-root-memory-identity/references.d.ts +95 -0
  227. package/dist/migrations/003-repository-root-memory-identity/references.js +469 -0
  228. package/dist/migrations/003-repository-root-memory-identity/repository-facts.d.ts +39 -0
  229. package/dist/migrations/003-repository-root-memory-identity/repository-facts.js +349 -0
  230. package/dist/migrations/__tests__/activation-concurrency.test.d.ts +1 -0
  231. package/dist/migrations/__tests__/activation-concurrency.test.js +145 -0
  232. package/dist/migrations/__tests__/activation.test.d.ts +1 -0
  233. package/dist/migrations/__tests__/activation.test.js +149 -0
  234. package/dist/migrations/__tests__/deletion-and-root-declaration.test.d.ts +1 -0
  235. package/dist/migrations/__tests__/deletion-and-root-declaration.test.js +149 -0
  236. package/dist/migrations/activation.d.ts +16 -0
  237. package/dist/migrations/activation.js +78 -0
  238. package/dist/migrations/convergent.d.ts +14 -3
  239. package/dist/migrations/convergent.js +21 -10
  240. package/dist/migrations/corpus.d.ts +78 -0
  241. package/dist/migrations/corpus.js +497 -0
  242. package/dist/migrations/frontmatter-splice.d.ts +15 -0
  243. package/dist/migrations/frontmatter-splice.js +176 -0
  244. package/dist/migrations/registry.d.ts +6 -1
  245. package/dist/migrations/registry.js +7 -2
  246. package/dist/migrations/runner.d.ts +41 -0
  247. package/dist/migrations/runner.js +81 -0
  248. package/dist/migrations/types.d.ts +148 -9
  249. package/dist/migrations/types.js +9 -2
  250. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +225 -17
  251. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +11 -3
  252. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -5
  253. package/dist/pi-extensions/canvas-context-intro.js +50 -46
  254. package/dist/pi-extensions/canvas-doc-substrate.d.ts +1 -8
  255. package/dist/pi-extensions/canvas-doc-substrate.js +55 -122
  256. package/dist/pi-extensions/canvas-stophook.js +6 -13
  257. package/dist/shared/generated-context.d.ts +0 -3
  258. package/dist/shared/generated-context.js +0 -57
  259. package/dist/shared/tool-groups.js +2 -3
  260. package/package.json +5 -4
  261. package/runtime.lock.json +2 -2
  262. /package/dist/api/__tests__/{serial → integration}/client.test.d.ts +0 -0
  263. /package/dist/api/__tests__/{serial → integration}/client.test.js +0 -0
  264. /package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{serial → integration}/provider-rotation.test.ts +0 -0
  265. /package/dist/clients/{inbox/__tests__/serial/inbox-controller.test.d.ts → attach/__tests__/pane-tag-successor.test.d.ts} +0 -0
  266. /package/dist/clients/{inbox/__tests__/serial/mount-panel.test.d.ts → attach/__tests__/profile-files.test.d.ts} +0 -0
  267. /package/dist/{core/__tests__/live-mutation-verbs.test.d.ts → clients/inbox/__tests__/integration/inbox-controller.test.d.ts} +0 -0
  268. /package/dist/clients/inbox/__tests__/{serial → integration}/inbox-controller.test.js +0 -0
  269. /package/dist/{core/__tests__/serial/broker-fork-seam.test.d.ts → clients/inbox/__tests__/integration/mount-panel.test.d.ts} +0 -0
  270. /package/dist/clients/inbox/__tests__/{serial → integration}/mount-panel.test.js +0 -0
  271. /package/dist/{core/__tests__/serial/broker-sdk-wiring.test.d.ts → commands/__tests__/surface-reload-target.test.d.ts} +0 -0
  272. /package/dist/{core/__tests__/serial/broker-snapshot-history.test.d.ts → commands/memory/__tests__/command-selector-and-mutation-guards.test.d.ts} +0 -0
  273. /package/dist/{core/__tests__/serial/command-plugins.test.d.ts → commands/memory/__tests__/repository-root-lint.test.d.ts} +0 -0
  274. /package/dist/{core/__tests__/serial/deferred-no-wake.test.d.ts → commands/sys/__tests__/sync-project-guidance.test.d.ts} +0 -0
  275. /package/dist/core/__tests__/{serial/flagship-lifecycle.test.d.ts → config-change-delta.test.d.ts} +0 -0
  276. /package/dist/core/__tests__/{serial/host-teardown-process-group.test.d.ts → integration/broker-fork-seam.test.d.ts} +0 -0
  277. /package/dist/core/__tests__/{serial/human-deliver-e2e.test.d.ts → integration/broker-sdk-wiring.test.d.ts} +0 -0
  278. /package/dist/core/__tests__/{serial/live-mutation.test.d.ts → integration/broker-snapshot-history.test.d.ts} +0 -0
  279. /package/dist/core/__tests__/{serial/refresh-stall-recycle.test.d.ts → integration/command-plugins.test.d.ts} +0 -0
  280. /package/dist/core/__tests__/{serial/revive.test.d.ts → integration/deferred-no-wake.test.d.ts} +0 -0
  281. /package/dist/core/__tests__/{serial/spawn-root.test.d.ts → integration/flagship-lifecycle.test.d.ts} +0 -0
  282. /package/dist/core/__tests__/{serial/subscription-delivery.test.d.ts → integration/host-teardown-process-group.test.d.ts} +0 -0
  283. /package/dist/core/__tests__/{serial/tmux-surface.test.d.ts → integration/human-deliver-e2e.test.d.ts} +0 -0
  284. /package/dist/core/__tests__/{serial/worktree.test.d.ts → integration/live-mutation-verbs.test.d.ts} +0 -0
  285. /package/dist/core/{human/__tests__/serial/inbox-core.test.d.ts → __tests__/integration/live-mutation.test.d.ts} +0 -0
  286. /package/dist/core/human/__tests__/{serial → integration}/inbox-core.test.js +0 -0
@@ -5,29 +5,9 @@
5
5
  // (registered in CANVAS_EXTENSIONS, src/core/runtime/launch.ts). INERT when
6
6
  // CRTR_NODE_ID is absent (a plain pi session or legacy job agent loads it as a no-op).
7
7
  //
8
- // It owns the substrate's pi hooks:
9
- //
10
- // 1. before_agent_start — the BOOT system-prompt half. Splices the rendered
11
- // `<memory kind="preference">` block (memory-usage guidance + preferences)
12
- // into `event.systemPrompt`, right after pi's native "Available tools" list
13
- // (before the `\n\nGuidelines:` anchor), so the substrate's standing
14
- // directives sit in the tool-selection frame the agent reads while choosing
15
- // a capability. Falls back to appending when the anchor is absent. (The `<memory kind="knowledge">`
16
- // catalog rides the bearings message instead — see core/substrate/render.ts.)
17
- //
18
- // 2. tool_result (gated on `read` and `bash`) — the EVENT half. For each
19
- // non-error `read`, evaluates the read file against every doc's `read`
20
- // surfaces entries across the resolved corpus and any project stores
21
- // enclosing the read file; for each non-error `bash`, evaluates the
22
- // executed command string against every doc's `command` entries. Matches
23
- // render at their matched rung in `<auto-loaded-context>` before the
24
- // tool output. A transcript-scoped (realpath → rung) map deduplicates
25
- // repeated deliveries and resumed broker processes.
26
- //
27
- // Both handler bodies are wrapped in try/catch and degrade to INERT on error —
28
- // a substrate bug must never brick node boot or break a `read`, only quietly
29
- // stop surfacing docs. The pure render lives in core/substrate/ (render.ts +
30
- // on-read.ts); this file is only the pi-hook plumbing.
8
+ // before_agent_start splices the context's frozen preference snapshot after the
9
+ // native tool list. Successful read/bash results append matching memory through
10
+ // the shared context exposure state. Pure rendering lives in core/substrate/.
31
11
  //
32
12
  // Plain TS-with-types — NO imports from @earendil-works/* (a local structural
33
13
  // PiLike interface stands in), so it compiles inside crouter's own tsc build
@@ -38,7 +18,7 @@ import { brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
38
18
  import { renderPreferencesFromState } from '../core/runtime/broker-extension-render.js';
39
19
  import { renderOnCommandDocsForSubject, renderOnReadDocsForSubject } from '../core/substrate/on-read.js';
40
20
  import { clearSessionCache } from '../core/substrate/session-cache.js';
41
- import { loadInjectedDocs, mergeInjectedDocs, saveInjectedDocs, sharedInjectedDocs } from '../core/substrate/injected-store.js';
21
+ import { cloneContextExposureState, exposureTarget, freezePreferenceSnapshot, loadContextExposureState, mergeContextExposureState, replaceContextExposureState, saveContextExposureState, sharedContextExposureState, } from '../core/substrate/injected-store.js';
42
22
  import { autoLoadedContextInner, mergeAutoLoadedContext } from './envelope-merge.js';
43
23
  // ---------------------------------------------------------------------------
44
24
  // Extension
@@ -48,120 +28,73 @@ import { autoLoadedContextInner, mergeAutoLoadedContext } from './envelope-merge
48
28
  * to reach for while reading the tools, so memory docs/preferences must sit
49
29
  * there, not far below. Falls back to appending if absent. */
50
30
  const TOOLS_ANCHOR = '\n\nGuidelines:';
51
- /**
52
- * Register the document substrate's pi hooks on `pi`.
53
- *
54
- * Returns immediately (inert) when CRTR_NODE_ID is absent — a non-canvas pi
55
- * session gets no hooks. Each handler is independently wrapped so a failure
56
- * degrades to a no-op (boot proceeds, the read returns) rather than bricking.
57
- */
58
31
  export function registerCanvasDocSubstrate(pi) {
59
32
  const nodeId = process.env['CRTR_NODE_ID'];
60
33
  if (nodeId === undefined || nodeId.trim() === '')
61
34
  return; // not a canvas node — inert
62
- // Per-TRANSCRIPT set of injected doc realpaths → a doc surfaces at most once
63
- // across the node's conversation, EVEN across a dormancy → revive(resume)
64
- // cycle. A resume reuses the same .jsonl transcript in a NEW pi process, so
65
- // the set is REHYDRATED from disk at process start (not started empty) and is
66
- // NOT cleared on session_start — a resume continues the transcript, so the
67
- // dedup must carry forward. The one launch path that begins a FRESH transcript
68
- // (reviveNode with resume=false) deletes the file, so a new conversation
69
- // rehydrates empty here. See core/substrate/injected-store.ts.
70
- //
71
- // The set is the PROCESS-SHARED instance (sharedInjectedDocs), so the
72
- // context-intro extension's workspace-open render grows the same set this
73
- // hook dedups against — a front door delivered at boot never re-delivers on
74
- // a later read beneath its store.
75
- const injectedDocs = sharedInjectedDocs(nodeId);
35
+ // One in-place state object is shared with context-intro and rehydrated on a
36
+ // strict resume. New-context launch paths clear it before baseline assembly.
37
+ const contextExposure = sharedContextExposureState(nodeId);
76
38
  pi.on('session_start', () => {
77
- // Only the per-session substrate PARSE cache resets each session (so the
78
- // corpus is re-scanned, picking up memory writes). injectedDocs is
79
- // transcript-scoped, not session-scoped — deliberately NOT cleared here.
80
39
  clearSessionCache();
81
40
  });
82
- // 1. BOOT system-prompt half — splice the `<memory kind="preference">` block
83
- // (memory-usage guidance + preferences). The guidance frame is always
84
- // present for a canvas node (the memory system always exists), so the block
85
- // is never empty even when no preference is eligible. (The knowledge catalog
86
- // does not enter the system prompt — it rides the bearings message via
87
- // renderKnowledgeBlock.)
88
41
  pi.on('before_agent_start', async (event) => {
89
- try {
42
+ mergeContextExposureState(contextExposure, loadContextExposureState(nodeId));
43
+ let block = contextExposure.preferenceSnapshot;
44
+ if (block === null) {
90
45
  const state = await brokerExtensionState(nodeId);
91
- // Merge the on-disk set first so this save never clobbers an
92
- // out-of-process delivery (the daemon's warm-spare bearings push), then
93
- // seed each rendered preference at its boot rung. Boot renders every
94
- // agent run and never skips; re-seeding at the same rung is idempotent.
95
- mergeInjectedDocs(injectedDocs, loadInjectedDocs(nodeId));
96
- const block = renderPreferencesFromState(state, injectedDocs);
97
- saveInjectedDocs(nodeId, injectedDocs);
98
- if (block === '')
99
- return; // nothing eligible — leave the prompt untouched
100
- const idx = event.systemPrompt.indexOf(TOOLS_ANCHOR);
101
- if (idx === -1) {
102
- return { systemPrompt: `${event.systemPrompt}\n\n${block}` };
103
- }
104
- return {
105
- systemPrompt: `${event.systemPrompt.slice(0, idx)}\n\n${block}${event.systemPrompt.slice(idx)}`,
106
- };
107
- }
108
- catch {
109
- return; // inert on error — never brick node boot
46
+ const next = cloneContextExposureState(contextExposure);
47
+ block = freezePreferenceSnapshot(next, renderPreferencesFromState(state, exposureTarget(next, 'system')));
48
+ saveContextExposureState(nodeId, next);
49
+ replaceContextExposureState(contextExposure, next);
110
50
  }
51
+ if (block === '')
52
+ return;
53
+ const idx = event.systemPrompt.indexOf(TOOLS_ANCHOR);
54
+ if (idx === -1)
55
+ return { systemPrompt: `${event.systemPrompt}\n\n${block}` };
56
+ return {
57
+ systemPrompt: `${event.systemPrompt.slice(0, idx)}\n\n${block}${event.systemPrompt.slice(idx)}`,
58
+ };
111
59
  });
112
- // 2. EVENT half — augment a non-error `read` with docs matched by the read
113
- // file, and a non-error `bash` with docs matched by the command string.
114
60
  pi.on('tool_result', async (event, ctx) => {
115
- try {
116
- if (event.isError === true)
117
- return;
118
- let injected;
119
- if (event.toolName === 'read') {
120
- const input = event.input;
121
- const rawPath = input?.path ?? input?.file_path;
122
- if (rawPath === undefined || rawPath === '')
123
- return;
124
- // Resolve to an absolute path (renderOnReadDocsForSubject realpaths it).
125
- // pi's read tool expands a leading `~`, but event.input keeps the raw
126
- // form, so expand it ourselves before resolving against the session cwd.
127
- const cwd = typeof ctx?.cwd === 'string' && ctx.cwd !== '' ? ctx.cwd : process.cwd();
128
- const expanded = rawPath.startsWith('~') ? join(homedir(), rawPath.slice(1)) : rawPath;
129
- const absFile = resolve(cwd, expanded);
130
- const state = await brokerExtensionState(nodeId);
131
- // Merge the on-disk set: an out-of-process delivery (the daemon's
132
- // warm-spare claim pushes bearings — including workspace-open docs —
133
- // into the live session and persists what it delivered) must dedup here
134
- // too. Cheap: one tiny JSON read per tool result.
135
- mergeInjectedDocs(injectedDocs, loadInjectedDocs(nodeId));
136
- injected = renderOnReadDocsForSubject(state.subject, absFile, injectedDocs);
137
- }
138
- else if (event.toolName === 'bash') {
139
- const input = event.input;
140
- const command = input?.command;
141
- if (typeof command !== 'string' || command.trim() === '')
142
- return;
143
- const state = await brokerExtensionState(nodeId);
144
- mergeInjectedDocs(injectedDocs, loadInjectedDocs(nodeId));
145
- injected = renderOnCommandDocsForSubject(state.subject, command, injectedDocs);
146
- }
147
- else {
61
+ if (event.isError === true)
62
+ return;
63
+ let readFile = null;
64
+ let command = null;
65
+ if (event.toolName === 'read') {
66
+ const input = event.input;
67
+ const rawPath = input?.path ?? input?.file_path;
68
+ if (rawPath === undefined || rawPath === '')
148
69
  return;
149
- }
150
- if (injected === '')
151
- return; // nothing surfaced — pass the result through unchanged
152
- // A doc surfaced → the render grew injectedDocs; persist the set so the
153
- // dedup survives a later dormancy → revive(resume).
154
- saveInjectedDocs(nodeId, injectedDocs);
155
- // Fold into any existing auto-loaded-context block from sibling hooks;
156
- // otherwise prepend one quiet block ahead of the tool output.
157
- const inner = autoLoadedContextInner(injected);
158
- if (inner === null)
70
+ const cwd = typeof ctx?.cwd === 'string' && ctx.cwd !== '' ? ctx.cwd : process.cwd();
71
+ const expanded = rawPath.startsWith('~') ? join(homedir(), rawPath.slice(1)) : rawPath;
72
+ readFile = resolve(cwd, expanded);
73
+ }
74
+ else if (event.toolName === 'bash') {
75
+ const input = event.input;
76
+ if (typeof input?.command !== 'string' || input.command.trim() === '')
159
77
  return;
160
- return { content: mergeAutoLoadedContext([inner], event.content) };
78
+ command = input.command;
161
79
  }
162
- catch {
163
- return; // inert on error — a bug must degrade a tool result, never break it
80
+ else {
81
+ return;
164
82
  }
83
+ const state = await brokerExtensionState(nodeId);
84
+ mergeContextExposureState(contextExposure, loadContextExposureState(nodeId));
85
+ const next = cloneContextExposureState(contextExposure);
86
+ const target = exposureTarget(next, 'transcript');
87
+ const injected = readFile !== null
88
+ ? renderOnReadDocsForSubject(state.subject, readFile, target)
89
+ : renderOnCommandDocsForSubject(state.subject, command, target);
90
+ if (injected === '')
91
+ return;
92
+ const inner = autoLoadedContextInner(injected);
93
+ if (inner === null)
94
+ throw new Error('substrate renderer returned an invalid auto-loaded context block');
95
+ saveContextExposureState(nodeId, next);
96
+ replaceContextExposureState(contextExposure, next);
97
+ return { content: mergeAutoLoadedContext([inner], event.content) };
165
98
  });
166
99
  }
167
100
  export default registerCanvasDocSubstrate;
@@ -25,9 +25,8 @@ import { join } from 'node:path';
25
25
  import { contextDir, jobDir } from '../core/canvas/paths.js';
26
26
  import { markBusy, clearBusy, touchBusy } from '../core/runtime/busy.js';
27
27
  import { clearFault } from '../core/runtime/fault.js';
28
- import { personaDriftFromBrokerState } from '../core/runtime/broker-persona-guidance.js';
29
28
  import { clearStopSignals, consumeStopSignals } from '../core/runtime/stop-signals.js';
30
- import { bindBrokerSession, brokerExtensionState, commitBrokerPersonaAck, relaunchBrokerRoot, settleBroker } from '../core/runtime/broker/daemon-ops.js';
29
+ import { bindBrokerSession, brokerExtensionState, relaunchBrokerRoot, settleBroker } from '../core/runtime/broker/daemon-ops.js';
31
30
  import { emitEvent } from '../core/events/emit.js';
32
31
  import { activeBackgroundBashJobs } from '../core/bash-jobs.js';
33
32
  import { CONTEXT_NUDGE_CUSTOM_TYPE, formatCard } from '../shared/generated-context.js';
@@ -376,6 +375,7 @@ export function registerCanvasStophook(pi) {
376
375
  fields: { operation: 'relaunch_root' },
377
376
  });
378
377
  });
378
+ return;
379
379
  }
380
380
  }
381
381
  catch (error) {
@@ -584,7 +584,8 @@ export function registerCanvasStophook(pi) {
584
584
  // is a ~2-token uncached delta each turn), so the bands were unreachable and
585
585
  // the nudge never fired.
586
586
  try {
587
- const node = (await brokerExtensionState(nodeId)).node;
587
+ const state = await brokerExtensionState(nodeId);
588
+ const node = state.node;
588
589
  const at = contextTokens !== null ? steerBand(contextTokens) : null;
589
590
  if (at !== null && !firedBands.has(at)) {
590
591
  firedBands.add(at);
@@ -596,17 +597,9 @@ export function registerCanvasStophook(pi) {
596
597
  pi.sendMessage({ customType: CONTEXT_NUDGE_CUSTOM_TYPE, content: note, display: true }, { deliverAs: 'nextTurn' });
597
598
  }
598
599
  }
599
- // Persona-transition steering. The daemon read snapshots both the
600
- // expected ack and current persona; its guarded ack below can only commit
601
- // exactly the transition this broker just described.
602
- const drift = personaDriftFromBrokerState(node);
603
- if (drift !== null) {
604
- pi.sendUserMessage(formatCard('persona-transition', {}, drift.guidance), { deliverAs: 'steer' });
605
- await commitBrokerPersonaAck(nodeId, { from: drift.from, to: drift.to });
606
- }
607
600
  }
608
- catch {
609
- /* steering is best-effort */
601
+ catch (error) {
602
+ emitDaemonOperationFailure('turn_boundary', error);
610
603
  }
611
604
  });
612
605
  // Pi may emit several agent_end attempts while it compacts, retries, and
@@ -6,8 +6,6 @@ export declare const SITUATIONAL_CONTEXT_CUSTOM_TYPE = "crtr-situational-context
6
6
  export declare const CONTEXT_NUDGE_CUSTOM_TYPE = "crtr-context-nudge";
7
7
  /** Custom message that opens a review companion's visible transcript. */
8
8
  export declare const REVIEW_BOUNDARY_CUSTOM_TYPE = "crtr-review-boundary";
9
- /** Opening text of a pre-envelope fresh-revive kickoff user message. */
10
- export declare const REVIVE_KICKOFF_SENTINEL = "You have been revived fresh after a context refresh";
11
9
  /** Generic completion mandate issued by the terminal-node stop guard. */
12
10
  export declare const STALL_REPROMPT: string;
13
11
  /** Static recovery prompts shared by the broker producer and display classifier. */
@@ -69,4 +67,3 @@ export declare function formatDataCard(kind: string, facts: Record<string, strin
69
67
  export declare function parseCard(message: GeneratedContextMessageLike): GeneratedCard | null;
70
68
  /** Format a complete inbox card from report bodies resolved by the caller. */
71
69
  export declare function formatInboxCard(sections: readonly InboxCardSection[]): string;
72
- export declare function isLegacyRuntimeText(text: string): boolean;
@@ -10,8 +10,6 @@ export const SITUATIONAL_CONTEXT_CUSTOM_TYPE = 'crtr-situational-context';
10
10
  export const CONTEXT_NUDGE_CUSTOM_TYPE = 'crtr-context-nudge';
11
11
  /** Custom message that opens a review companion's visible transcript. */
12
12
  export const REVIEW_BOUNDARY_CUSTOM_TYPE = 'crtr-review-boundary';
13
- /** Opening text of a pre-envelope fresh-revive kickoff user message. */
14
- export const REVIVE_KICKOFF_SENTINEL = 'You have been revived fresh after a context refresh';
15
13
  /** Generic completion mandate issued by the terminal-node stop guard. */
16
14
  export const STALL_REPROMPT = "You've stopped but you're not waiting on anyone and haven't finished. " +
17
15
  "Pipe the result to `crtr push final` through a single-quoted heredoc if the work is done, or use `crtr human send` if you are blocked or need the user.";
@@ -212,58 +210,3 @@ export function formatInboxCard(sections) {
212
210
  }).join('\n');
213
211
  return formatCard('inbox', {}, body);
214
212
  }
215
- // LEGACY — landed 2026-08-14. Pre-envelope runtime text, kept ONLY so old
216
- // scrollback is not attributed to the person. Delete this section and its
217
- // callers one week after that date; after deletion, pre-cut scrollback
218
- // misattributes and that cost is accepted.
219
- const LEGACY_RESTART_CONTINUATION = '<runtime-restart-continuation>\ncontinue\n</runtime-restart-continuation>';
220
- const CONTEXT_NUDGE_PREFIX = '[crtr] Context ~';
221
- const PERSONA_TRANSITION_OPEN = '<persona-transition>';
222
- const PERSONA_TRANSITION_CLOSE = '</persona-transition>';
223
- const INBOX_SENDER_ID = '[a-z0-9]+(?:-[a-z0-9]+)+';
224
- const INBOX_HEADER_RE = new RegExp(`^From (?:(.+?) \\[(${INBOX_SENDER_ID})\\]|(${INBOX_SENDER_ID}|system|human|crtrd)) — (\\d+) update`, 'm');
225
- function isPersonaTransition(body) {
226
- return body.startsWith(`${PERSONA_TRANSITION_OPEN}\n`) && body.endsWith(`\n${PERSONA_TRANSITION_CLOSE}`);
227
- }
228
- function isReviewApproval(body) {
229
- return body.startsWith(`${REVIEW_APPROVAL_OPEN}\n`) && body.endsWith(`\n${REVIEW_APPROVAL_CLOSE}`);
230
- }
231
- function isStructuredOutputReprompt(body) {
232
- if (!body.startsWith(STRUCTURED_OUTPUT_REPROMPT_PREFIX) || !body.endsWith(STRUCTURED_OUTPUT_REPROMPT_SUFFIX)) {
233
- return false;
234
- }
235
- const schema = body.slice(STRUCTURED_OUTPUT_REPROMPT_PREFIX.length, -STRUCTURED_OUTPUT_REPROMPT_SUFFIX.length);
236
- try {
237
- JSON.parse(schema);
238
- return true;
239
- }
240
- catch {
241
- return false;
242
- }
243
- }
244
- const MODEL_CREDENTIAL_RECOVERY_RE = /^The previous model \([^\n]+\) had no usable provider credential, so you were automatically switched to [^\n]+\. Continue the task from where the failed turn left off\.$/;
245
- const MODEL_NOT_FOUND_RECOVERY_RE = /^The previous model \([^\n]+\) was unavailable \(provider 404 not_found\), so you were automatically switched to [^\n]+\. Continue the task from where the failed turn left off\.$/;
246
- function isModelFallbackRecovery(body) {
247
- if (!body.startsWith(`${MODEL_FALLBACK_RECOVERY_OPEN}\n`) || !body.endsWith(`\n${MODEL_FALLBACK_RECOVERY_CLOSE}`)) {
248
- return false;
249
- }
250
- const guidance = body.slice(MODEL_FALLBACK_RECOVERY_OPEN.length + 1, -(MODEL_FALLBACK_RECOVERY_CLOSE.length + 1));
251
- return MODEL_CREDENTIAL_RECOVERY_RE.test(guidance) || MODEL_NOT_FOUND_RECOVERY_RE.test(guidance);
252
- }
253
- function isRecoveryBody(body) {
254
- return body === AUTH_FAULT_RECOVERY_BODY
255
- || body === CONNECTION_FAULT_RECOVERY_BODY
256
- || body === PROVIDER_FAULT_RECOVERY_BODY
257
- || body === LEGACY_RESTART_CONTINUATION
258
- || isModelFallbackRecovery(body);
259
- }
260
- export function isLegacyRuntimeText(text) {
261
- return text.startsWith(REVIVE_KICKOFF_SENTINEL)
262
- || text.startsWith(CONTEXT_NUDGE_PREFIX)
263
- || INBOX_HEADER_RE.test(text)
264
- || isReviewApproval(text)
265
- || isPersonaTransition(text)
266
- || text === STALL_REPROMPT
267
- || isStructuredOutputReprompt(text)
268
- || isRecoveryBody(text);
269
- }
@@ -1,7 +1,7 @@
1
1
  // Shared transcript-boundary rules for broker-owned tool-group summaries.
2
2
  // Keep this independent of renderer state: both live event tracking and snapshot
3
3
  // reconstruction must agree on which prose closes a run of tools.
4
- import { generatedContextText, isLegacyRuntimeText, parseCard } from './generated-context.js';
4
+ import { generatedContextText, parseCard } from './generated-context.js';
5
5
  /** Card kinds that close a run of tools instead of joining one. The broker
6
6
  * segments and the viewer folds on the same seams, so this one answer is shared;
7
7
  * everything else about a card is the display's own business. */
@@ -60,6 +60,5 @@ export function assistantVisibleText(message) {
60
60
  /** A person-authored user message closes the preceding group. Runtime-generated
61
61
  * user context retains role=user for delivery semantics but is not human prose. */
62
62
  export function isTrueUserMessage(message) {
63
- const text = generatedContextText(message);
64
- return message.role === 'user' && parseCard(message) === null && !isLegacyRuntimeText(text);
63
+ return message.role === 'user' && parseCard(message) === null;
65
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.227",
3
+ "version": "0.3.228",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -81,10 +81,11 @@
81
81
  "dev": "tsx --conditions=crtr-src src/cli.ts",
82
82
  "link": "npm link",
83
83
  "prepublishOnly": "npm run build",
84
- "test": "node --conditions=crtr-src --import tsx/esm --test --test-concurrency=4 --test-timeout=10000 'src/**/__tests__/*.test.ts'",
85
- "test:serial": "node --conditions=crtr-src --import tsx/esm --test --test-concurrency=1 --test-timeout=60000 'src/**/__tests__/serial/*.test.ts'",
84
+ "test": "node --conditions=crtr-src --import tsx/esm --test --test-force-exit --test-concurrency=$(node -p 'Math.max(4, require(`node:os`).availableParallelism() - 1)') --test-timeout=10000 'src/**/__tests__/*.test.ts'",
85
+ "test:integration": "node --conditions=crtr-src --import tsx/esm --test --test-concurrency=$(node -p 'Math.min(8, Math.max(2, require(`node:os`).availableParallelism() - 1))') --test-timeout=60000 'src/**/__tests__/integration/*.test.ts'",
86
86
  "test:seam": "npm run build && npm run test:seam:built",
87
- "test:seam:built": "node --test --test-concurrency=2 --test-timeout=180000 'dist/**/__tests__/seam/*.test.js'"
87
+ "test:seam:built": "node --test --test-concurrency=4 --test-timeout=180000 'dist/**/__tests__/seam/*.test.js'",
88
+ "test:all": "npm test && npm run test:integration && npm run test:seam"
88
89
  },
89
90
  "overrides": {
90
91
  "@earendil-works/pi-ai": "0.84.1",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.227",
3
+ "version": "0.3.228",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.227",
9
+ "version": "0.3.228",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {