@crouton-kit/crouter 0.3.32 → 0.3.33

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 (440) hide show
  1. package/README.md +8 -0
  2. package/dist/build-root.js +1 -0
  3. package/dist/builtin-memory/crouter-development/marketplaces.md +2 -2
  4. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +2 -2
  5. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +5 -5
  6. package/dist/builtin-memory/crouter-development/personas.md +3 -4
  7. package/dist/builtin-memory/crouter-development/plugins.md +18 -18
  8. package/dist/builtin-memory/design.md +4 -1
  9. package/dist/builtin-memory/development.md +4 -1
  10. package/dist/builtin-memory/internal/INDEX.md +1 -1
  11. package/dist/builtin-memory/internal/nodes-and-canvas.md +6 -6
  12. package/dist/builtin-memory/internal/storage-tiers.md +5 -5
  13. package/dist/builtin-memory/planning.md +4 -1
  14. package/dist/builtin-memory/product.md +80 -0
  15. package/dist/builtin-memory/spec.md +4 -1
  16. package/dist/builtin-personas/advisor/PERSONA.md +10 -0
  17. package/dist/builtin-personas/design/PERSONA.md +2 -2
  18. package/dist/builtin-personas/design/orchestrator.md +3 -3
  19. package/dist/builtin-personas/developer/PERSONA.md +1 -1
  20. package/dist/builtin-personas/developer/orchestrator.md +2 -2
  21. package/dist/builtin-personas/explore/PERSONA.md +3 -3
  22. package/dist/builtin-personas/explore/orchestrator.md +4 -2
  23. package/dist/builtin-personas/general/PERSONA.md +1 -1
  24. package/dist/builtin-personas/general/orchestrator.md +1 -1
  25. package/dist/builtin-personas/orchestration-kernel.md +7 -14
  26. package/dist/builtin-personas/plan/PERSONA.md +1 -1
  27. package/dist/builtin-personas/plan/orchestrator.md +2 -2
  28. package/dist/builtin-personas/plan/reviewers/architecture-fit/PERSONA.md +1 -1
  29. package/dist/builtin-personas/plan/reviewers/code-smells/PERSONA.md +1 -1
  30. package/dist/builtin-personas/plan/reviewers/pattern-consistency/PERSONA.md +1 -1
  31. package/dist/builtin-personas/plan/reviewers/requirements-coverage/PERSONA.md +1 -1
  32. package/dist/builtin-personas/plan/reviewers/security/PERSONA.md +1 -1
  33. package/dist/builtin-personas/product/PERSONA.md +18 -0
  34. package/dist/builtin-personas/product/orchestrator.md +14 -0
  35. package/dist/builtin-personas/product/teardown/PERSONA.md +13 -0
  36. package/dist/builtin-personas/review/PERSONA.md +1 -1
  37. package/dist/builtin-personas/review/orchestrator.md +1 -1
  38. package/dist/builtin-personas/runtime-base.md +5 -0
  39. package/dist/builtin-personas/spec/PERSONA.md +1 -1
  40. package/dist/builtin-personas/spec/orchestrator.md +2 -2
  41. package/dist/builtin-personas/spec/requirements/PERSONA.md +1 -1
  42. package/dist/builtin-views/canvas/core.mjs +82 -1
  43. package/dist/builtin-views/canvas/tui.mjs +9 -5
  44. package/dist/builtin-views/canvas/web.jsx +3 -2
  45. package/dist/builtin-views/chat/core.mjs +725 -0
  46. package/dist/builtin-views/chat/text.mjs +101 -0
  47. package/dist/builtin-views/chat/tui.mjs +368 -0
  48. package/dist/builtin-views/chat/web.jsx +367 -0
  49. package/dist/builtin-views/prompt-review/core.mjs +863 -0
  50. package/dist/builtin-views/prompt-review/text.mjs +15 -0
  51. package/dist/builtin-views/prompt-review/tui.mjs +196 -0
  52. package/dist/builtin-views/prompt-review/web.jsx +484 -0
  53. package/dist/builtin-views/settings/core.mjs +397 -0
  54. package/dist/builtin-views/settings/text.mjs +40 -0
  55. package/dist/builtin-views/settings/tui.mjs +95 -0
  56. package/dist/builtin-views/settings/web.jsx +167 -0
  57. package/dist/cli.js +16 -3
  58. package/dist/clients/attach/__tests__/autocomplete-and-bash-mode.test.js +96 -0
  59. package/dist/clients/attach/__tests__/bash-bang-routing.test.js +58 -0
  60. package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.d.ts +1 -0
  61. package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.js +56 -0
  62. package/dist/clients/attach/__tests__/titled-editor.test.js +22 -1
  63. package/dist/clients/attach/attach-cmd.d.ts +18 -0
  64. package/dist/clients/attach/attach-cmd.js +1723 -795
  65. package/dist/clients/attach/canvas-panels.js +2 -2
  66. package/dist/clients/attach/chat-view.d.ts +10 -0
  67. package/dist/clients/attach/chat-view.js +23 -0
  68. package/dist/clients/attach/config-load.d.ts +8 -4
  69. package/dist/clients/attach/config-load.js +2 -0
  70. package/dist/clients/attach/extension-dialogs.d.ts +2 -3
  71. package/dist/clients/attach/extension-dialogs.js +7 -9
  72. package/dist/clients/attach/graph-overlay.js +3 -2
  73. package/dist/clients/attach/input-controller.d.ts +4 -3
  74. package/dist/clients/attach/input-controller.js +24 -3
  75. package/dist/clients/attach/slash-commands.d.ts +7 -7
  76. package/dist/clients/attach/slash-commands.js +38 -14
  77. package/dist/clients/attach/titled-editor.js +18 -14
  78. package/dist/clients/attach/view-socket.d.ts +2 -1
  79. package/dist/clients/attach/view-socket.js +27 -8
  80. package/dist/clients/web/__tests__/source-cache.test.d.ts +1 -0
  81. package/dist/clients/web/__tests__/source-cache.test.js +32 -0
  82. package/dist/clients/web/dev-server.js +1 -0
  83. package/dist/clients/web/events.js +9 -11
  84. package/dist/clients/web/server.d.ts +4 -3
  85. package/dist/clients/web/server.js +138 -31
  86. package/dist/clients/web/source-cache.d.ts +10 -0
  87. package/dist/clients/web/source-cache.js +57 -0
  88. package/dist/clients/web/web-cmd.js +28 -9
  89. package/dist/commands/__tests__/human.test.js +30 -28
  90. package/dist/commands/canvas-history/search.js +1 -1
  91. package/dist/commands/canvas-history.js +5 -8
  92. package/dist/commands/canvas-issue.d.ts +2 -0
  93. package/dist/commands/canvas-issue.js +148 -0
  94. package/dist/commands/canvas-prune.js +19 -0
  95. package/dist/commands/canvas-rebuild-index.d.ts +2 -0
  96. package/dist/commands/canvas-rebuild-index.js +57 -0
  97. package/dist/commands/canvas-snapshot.d.ts +2 -0
  98. package/dist/commands/canvas-snapshot.js +48 -0
  99. package/dist/commands/canvas-tmux-spread.d.ts +2 -0
  100. package/dist/commands/canvas-tmux-spread.js +188 -0
  101. package/dist/commands/canvas.d.ts +1 -0
  102. package/dist/commands/canvas.js +16 -1
  103. package/dist/commands/chord.js +143 -48
  104. package/dist/commands/daemon.js +3 -3
  105. package/dist/commands/human/prompts.d.ts +0 -1
  106. package/dist/commands/human/prompts.js +39 -54
  107. package/dist/commands/human/queue.d.ts +12 -1
  108. package/dist/commands/human/queue.js +468 -73
  109. package/dist/commands/human/shared.d.ts +3 -4
  110. package/dist/commands/human/shared.js +3 -3
  111. package/dist/commands/human.js +11 -10
  112. package/dist/commands/memory/find.js +3 -2
  113. package/dist/commands/memory/list.js +4 -3
  114. package/dist/commands/memory/read.js +3 -3
  115. package/dist/commands/memory/shared.d.ts +1 -4
  116. package/dist/commands/memory/shared.js +6 -9
  117. package/dist/commands/memory/write.js +3 -3
  118. package/dist/commands/memory.js +4 -7
  119. package/dist/commands/node-context.d.ts +2 -0
  120. package/dist/commands/node-context.js +172 -0
  121. package/dist/commands/node-snapshot.d.ts +2 -0
  122. package/dist/commands/node-snapshot.js +123 -0
  123. package/dist/commands/node.js +228 -52
  124. package/dist/commands/pkg/plugin-inspect.js +6 -6
  125. package/dist/commands/pkg/plugin-manage.js +1 -1
  126. package/dist/commands/pkg/plugin.js +2 -2
  127. package/dist/commands/pkg.js +2 -2
  128. package/dist/commands/push.d.ts +2 -0
  129. package/dist/commands/push.js +79 -11
  130. package/dist/commands/revive.js +74 -1
  131. package/dist/commands/search/answer.d.ts +1 -0
  132. package/dist/commands/search/answer.js +50 -0
  133. package/dist/commands/search/contents.d.ts +1 -0
  134. package/dist/commands/search/contents.js +96 -0
  135. package/dist/commands/search/exa.d.ts +53 -0
  136. package/dist/commands/search/exa.js +155 -0
  137. package/dist/commands/search/puremd.d.ts +11 -0
  138. package/dist/commands/search/puremd.js +53 -0
  139. package/dist/commands/search/web.d.ts +1 -0
  140. package/dist/commands/search/web.js +65 -0
  141. package/dist/commands/search.d.ts +2 -0
  142. package/dist/commands/search.js +24 -0
  143. package/dist/commands/sys/__tests__/sync-import.test.d.ts +1 -0
  144. package/dist/commands/sys/__tests__/sync-import.test.js +72 -0
  145. package/dist/commands/sys/config.js +59 -10
  146. package/dist/commands/sys/doctor.js +56 -4
  147. package/dist/commands/sys/prompt-review.d.ts +1 -0
  148. package/dist/commands/sys/prompt-review.js +178 -0
  149. package/dist/commands/sys/promptstudio.d.ts +2 -0
  150. package/dist/commands/sys/promptstudio.js +65 -0
  151. package/dist/commands/sys/settings.d.ts +2 -0
  152. package/dist/commands/sys/settings.js +16 -0
  153. package/dist/commands/sys/sync.js +311 -159
  154. package/dist/commands/sys/sysprompt.d.ts +1 -0
  155. package/dist/commands/sys/sysprompt.js +86 -0
  156. package/dist/commands/sys.js +9 -5
  157. package/dist/commands/view-new.js +2 -2
  158. package/dist/core/__tests__/artifact-paths.test.d.ts +1 -0
  159. package/dist/core/__tests__/artifact-paths.test.js +44 -0
  160. package/dist/core/__tests__/broker-preflight.test.d.ts +1 -0
  161. package/dist/core/__tests__/broker-preflight.test.js +85 -0
  162. package/dist/core/__tests__/broker-sdk-wiring.test.js +15 -0
  163. package/dist/core/__tests__/canvas.test.js +37 -1
  164. package/dist/core/__tests__/chat-view-reconnect.test.d.ts +1 -0
  165. package/dist/core/__tests__/chat-view-reconnect.test.js +70 -0
  166. package/dist/core/__tests__/child-death-wake.test.js +11 -2
  167. package/dist/core/__tests__/close.test.js +39 -1
  168. package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +1 -0
  169. package/dist/core/__tests__/connection-reconnect-resume.test.js +37 -0
  170. package/dist/core/__tests__/context-intro.test.js +48 -14
  171. package/dist/core/__tests__/daemon-boot.test.js +182 -9
  172. package/dist/core/__tests__/editor-label.test.d.ts +1 -0
  173. package/dist/core/__tests__/editor-label.test.js +26 -0
  174. package/dist/core/__tests__/fault-marker.test.d.ts +1 -0
  175. package/dist/core/__tests__/fault-marker.test.js +112 -0
  176. package/dist/core/__tests__/fault-retry-rewind.test.d.ts +1 -0
  177. package/dist/core/__tests__/fault-retry-rewind.test.js +123 -0
  178. package/dist/core/__tests__/fixtures/fake-engine.d.ts +30 -4
  179. package/dist/core/__tests__/fixtures/fake-engine.js +156 -17
  180. package/dist/core/__tests__/fixtures/fake-pi-host.js +10 -1
  181. package/dist/core/__tests__/full/human-new-window-regression.test.js +1 -1
  182. package/dist/core/__tests__/helpers/harness.d.ts +1 -1
  183. package/dist/core/__tests__/helpers/harness.js +2 -2
  184. package/dist/core/__tests__/human-stranded-deliver.test.js +38 -1
  185. package/dist/core/__tests__/human-surface-target.test.js +1 -1
  186. package/dist/core/__tests__/kickoff.test.js +18 -19
  187. package/dist/core/__tests__/memory-resolver.test.js +12 -1
  188. package/dist/core/__tests__/migration.test.js +49 -14
  189. package/dist/core/__tests__/model-ladders.test.d.ts +1 -0
  190. package/dist/core/__tests__/model-ladders.test.js +160 -0
  191. package/dist/core/__tests__/node-env.test.d.ts +1 -0
  192. package/dist/core/__tests__/node-env.test.js +26 -0
  193. package/dist/core/__tests__/push-final-guard.test.js +7 -1
  194. package/dist/core/__tests__/relaunch-root.test.js +9 -9
  195. package/dist/core/__tests__/revive.test.js +36 -6
  196. package/dist/core/__tests__/spawn-root.test.js +24 -1
  197. package/dist/core/__tests__/stop-guard.test.js +10 -0
  198. package/dist/core/__tests__/stranded-relaunch.test.d.ts +1 -0
  199. package/dist/core/__tests__/stranded-relaunch.test.js +72 -0
  200. package/dist/core/__tests__/tmux-surface.test.js +5 -1
  201. package/dist/core/__tests__/unknown-path.test.js +19 -19
  202. package/dist/core/__tests__/yield-ensures-daemon.test.d.ts +1 -0
  203. package/dist/core/__tests__/yield-ensures-daemon.test.js +54 -0
  204. package/dist/core/artifact.d.ts +2 -33
  205. package/dist/core/artifact.js +27 -87
  206. package/dist/core/bootstrap.js +2 -0
  207. package/dist/core/canvas/browse/__tests__/model.test.js +35 -1
  208. package/dist/core/canvas/browse/app.js +87 -17
  209. package/dist/core/canvas/browse/model.d.ts +10 -1
  210. package/dist/core/canvas/browse/model.js +37 -1
  211. package/dist/core/canvas/browse/render.js +35 -33
  212. package/dist/core/canvas/canvas.d.ts +7 -0
  213. package/dist/core/canvas/canvas.js +54 -5
  214. package/dist/core/canvas/db.js +35 -8
  215. package/dist/core/canvas/labels.d.ts +6 -8
  216. package/dist/core/canvas/labels.js +8 -11
  217. package/dist/core/canvas/nav-model.d.ts +5 -4
  218. package/dist/core/canvas/nav-model.js +31 -17
  219. package/dist/core/canvas/paths.d.ts +18 -1
  220. package/dist/core/canvas/paths.js +31 -2
  221. package/dist/core/canvas/render.d.ts +25 -0
  222. package/dist/core/canvas/render.js +96 -13
  223. package/dist/core/canvas/status-glyph.d.ts +35 -0
  224. package/dist/core/canvas/status-glyph.js +104 -0
  225. package/dist/core/canvas/types.d.ts +2 -2
  226. package/dist/core/config.js +114 -16
  227. package/dist/core/fault-classifier.d.ts +41 -0
  228. package/dist/core/fault-classifier.js +110 -0
  229. package/dist/core/feed/inbox.d.ts +15 -0
  230. package/dist/core/feed/inbox.js +40 -14
  231. package/dist/core/frontmatter.d.ts +1 -11
  232. package/dist/core/frontmatter.js +1 -55
  233. package/dist/core/hearth/config.d.ts +2 -0
  234. package/dist/core/hearth/config.js +75 -0
  235. package/dist/core/hearth/guest-env.d.ts +2 -0
  236. package/dist/core/hearth/guest-env.js +11 -0
  237. package/dist/core/hearth/index.d.ts +5 -0
  238. package/dist/core/hearth/index.js +5 -0
  239. package/dist/core/hearth/provider.d.ts +21 -0
  240. package/dist/core/hearth/provider.js +10 -0
  241. package/dist/core/hearth/providers/blaxel-bootstrap.d.ts +10 -0
  242. package/dist/core/hearth/providers/blaxel-bootstrap.js +39 -0
  243. package/dist/core/hearth/providers/blaxel-home.d.ts +11 -0
  244. package/dist/core/hearth/providers/blaxel-home.js +126 -0
  245. package/dist/core/hearth/providers/blaxel.d.ts +26 -0
  246. package/dist/core/hearth/providers/blaxel.js +208 -0
  247. package/dist/core/hearth/providers/types.d.ts +72 -0
  248. package/dist/core/hearth/providers/types.js +1 -0
  249. package/dist/core/hearth/registry.d.ts +15 -0
  250. package/dist/core/hearth/registry.js +179 -0
  251. package/dist/core/hearth/types.d.ts +121 -0
  252. package/dist/core/hearth/types.js +1 -0
  253. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +1 -0
  254. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +79 -0
  255. package/dist/core/{skill-sync → host-exports}/builtins.d.ts +21 -13
  256. package/dist/core/host-exports/builtins.js +68 -0
  257. package/dist/core/{skill-sync → host-exports}/export.d.ts +9 -6
  258. package/dist/core/{skill-sync → host-exports}/export.js +37 -14
  259. package/dist/core/io.js +1 -1
  260. package/dist/core/log.d.ts +9 -0
  261. package/dist/core/log.js +113 -0
  262. package/dist/core/memory-resolver.d.ts +8 -8
  263. package/dist/core/memory-resolver.js +15 -28
  264. package/dist/core/personas/index.d.ts +4 -4
  265. package/dist/core/personas/index.js +2 -2
  266. package/dist/core/personas/loader.d.ts +51 -0
  267. package/dist/core/personas/loader.js +54 -50
  268. package/dist/core/personas/resolve.d.ts +43 -27
  269. package/dist/core/personas/resolve.js +336 -94
  270. package/dist/core/runtime/auth-reload.d.ts +7 -0
  271. package/dist/core/runtime/auth-reload.js +69 -0
  272. package/dist/core/runtime/bearings.d.ts +35 -15
  273. package/dist/core/runtime/bearings.js +305 -44
  274. package/dist/core/runtime/branded-host.d.ts +4 -2
  275. package/dist/core/runtime/branded-host.js +66 -4
  276. package/dist/core/runtime/broker-protocol.d.ts +38 -3
  277. package/dist/core/runtime/broker.js +343 -18
  278. package/dist/core/runtime/close.js +37 -29
  279. package/dist/core/runtime/connectivity.d.ts +12 -0
  280. package/dist/core/runtime/connectivity.js +73 -0
  281. package/dist/core/runtime/fault-recovery-nudge.d.ts +2 -0
  282. package/dist/core/runtime/fault-recovery-nudge.js +2 -0
  283. package/dist/core/runtime/fault-recovery.d.ts +23 -0
  284. package/dist/core/runtime/fault-recovery.js +74 -0
  285. package/dist/core/runtime/fault.d.ts +25 -0
  286. package/dist/core/runtime/fault.js +176 -0
  287. package/dist/core/runtime/front-door.d.ts +1 -1
  288. package/dist/core/runtime/front-door.js +2 -2
  289. package/dist/core/runtime/host.d.ts +10 -0
  290. package/dist/core/runtime/host.js +71 -9
  291. package/dist/core/runtime/kickoff.js +31 -45
  292. package/dist/core/runtime/launch.d.ts +32 -18
  293. package/dist/core/runtime/launch.js +148 -43
  294. package/dist/core/runtime/model-swap.d.ts +18 -0
  295. package/dist/core/runtime/model-swap.js +95 -0
  296. package/dist/core/runtime/naming.d.ts +7 -0
  297. package/dist/core/runtime/naming.js +61 -9
  298. package/dist/core/runtime/nodes.js +6 -1
  299. package/dist/core/runtime/persona.js +16 -17
  300. package/dist/core/runtime/placement.d.ts +36 -31
  301. package/dist/core/runtime/placement.js +149 -64
  302. package/dist/core/runtime/promote.d.ts +2 -0
  303. package/dist/core/runtime/promote.js +23 -3
  304. package/dist/core/runtime/recycle.js +6 -4
  305. package/dist/core/runtime/reset.d.ts +5 -2
  306. package/dist/core/runtime/reset.js +2 -2
  307. package/dist/core/runtime/revive.d.ts +4 -0
  308. package/dist/core/runtime/revive.js +27 -9
  309. package/dist/core/runtime/roadmap.d.ts +1 -1
  310. package/dist/core/runtime/roadmap.js +1 -1
  311. package/dist/core/runtime/spawn.d.ts +2 -2
  312. package/dist/core/runtime/spawn.js +30 -6
  313. package/dist/core/runtime/stop-guard.js +6 -1
  314. package/dist/core/runtime/tmux-chrome.d.ts +1 -1
  315. package/dist/core/runtime/tmux-chrome.js +1 -1
  316. package/dist/core/runtime/tmux.d.ts +29 -6
  317. package/dist/core/runtime/tmux.js +134 -80
  318. package/dist/core/runtime/view-socket-client.d.ts +46 -0
  319. package/dist/core/runtime/view-socket-client.js +203 -0
  320. package/dist/core/substrate/index.d.ts +1 -1
  321. package/dist/core/substrate/index.js +1 -1
  322. package/dist/core/substrate/on-read.js +16 -4
  323. package/dist/core/substrate/render.d.ts +10 -13
  324. package/dist/core/substrate/render.js +56 -51
  325. package/dist/core/tui/host.js +83 -18
  326. package/dist/core/view/__tests__/transport-cache.test.d.ts +1 -0
  327. package/dist/core/view/__tests__/transport-cache.test.js +62 -0
  328. package/dist/core/view/contract.d.ts +20 -0
  329. package/dist/core/view/stream-local.d.ts +3 -0
  330. package/dist/core/view/stream-local.js +184 -0
  331. package/dist/core/view/transport-cache.d.ts +8 -0
  332. package/dist/core/view/transport-cache.js +38 -0
  333. package/dist/core/view/transport-local.js +4 -0
  334. package/dist/core/view/transport.d.ts +7 -1
  335. package/dist/daemon/crtrd.d.ts +3 -19
  336. package/dist/daemon/crtrd.js +139 -178
  337. package/dist/daemon/manage.d.ts +18 -1
  338. package/dist/daemon/manage.js +54 -9
  339. package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.d.ts +1 -0
  340. package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.js +289 -0
  341. package/dist/hearth/wake-proxy/__tests__/config-timeout.test.d.ts +1 -0
  342. package/dist/hearth/wake-proxy/__tests__/config-timeout.test.js +34 -0
  343. package/dist/hearth/wake-proxy/__tests__/guest-source.test.d.ts +1 -0
  344. package/dist/hearth/wake-proxy/__tests__/guest-source.test.js +203 -0
  345. package/dist/hearth/wake-proxy/__tests__/hardening.test.d.ts +1 -0
  346. package/dist/hearth/wake-proxy/__tests__/hardening.test.js +59 -0
  347. package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.d.ts +1 -0
  348. package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.js +372 -0
  349. package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.d.ts +1 -0
  350. package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.js +258 -0
  351. package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.d.ts +1 -0
  352. package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.js +437 -0
  353. package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.d.ts +1 -0
  354. package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.js +455 -0
  355. package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.d.ts +1 -0
  356. package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.js +15 -0
  357. package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.d.ts +1 -0
  358. package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.js +141 -0
  359. package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.d.ts +1 -0
  360. package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.js +143 -0
  361. package/dist/hearth/wake-proxy/anthropic-oauth.d.ts +58 -0
  362. package/dist/hearth/wake-proxy/anthropic-oauth.js +189 -0
  363. package/dist/hearth/wake-proxy/auth.d.ts +22 -0
  364. package/dist/hearth/wake-proxy/auth.js +128 -0
  365. package/dist/hearth/wake-proxy/config.d.ts +2 -0
  366. package/dist/hearth/wake-proxy/config.js +151 -0
  367. package/dist/hearth/wake-proxy/guest-source.d.ts +14 -0
  368. package/dist/hearth/wake-proxy/guest-source.js +130 -0
  369. package/dist/hearth/wake-proxy/hearth-status.d.ts +44 -0
  370. package/dist/hearth/wake-proxy/hearth-status.js +267 -0
  371. package/dist/hearth/wake-proxy/home.d.ts +67 -0
  372. package/dist/hearth/wake-proxy/home.js +297 -0
  373. package/dist/hearth/wake-proxy/main.d.ts +1 -0
  374. package/dist/hearth/wake-proxy/main.js +134 -0
  375. package/dist/hearth/wake-proxy/model-auth.d.ts +13 -0
  376. package/dist/hearth/wake-proxy/model-auth.js +345 -0
  377. package/dist/hearth/wake-proxy/proxy.d.ts +35 -0
  378. package/dist/hearth/wake-proxy/proxy.js +716 -0
  379. package/dist/hearth/wake-proxy/public-source-gate.d.ts +9 -0
  380. package/dist/hearth/wake-proxy/public-source-gate.js +409 -0
  381. package/dist/hearth/wake-proxy/redact.d.ts +1 -0
  382. package/dist/hearth/wake-proxy/redact.js +17 -0
  383. package/dist/hearth/wake-proxy/server.d.ts +11 -0
  384. package/dist/hearth/wake-proxy/server.js +142 -0
  385. package/dist/hearth/wake-proxy/state.d.ts +18 -0
  386. package/dist/hearth/wake-proxy/state.js +342 -0
  387. package/dist/hearth/wake-proxy/types.d.ts +76 -0
  388. package/dist/hearth/wake-proxy/types.js +1 -0
  389. package/dist/index.js +3 -2
  390. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +6 -5
  391. package/dist/pi-extensions/canvas-context-intro.js +7 -7
  392. package/dist/pi-extensions/canvas-doc-substrate.js +19 -22
  393. package/dist/pi-extensions/canvas-nav.js +15 -8
  394. package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
  395. package/dist/pi-extensions/canvas-stophook.js +78 -11
  396. package/dist/types.d.ts +39 -20
  397. package/dist/types.js +38 -13
  398. package/dist/web/runtime.js +141 -42
  399. package/dist/web/transport-http.js +7 -5
  400. package/dist/web/transport-stream.d.ts +3 -0
  401. package/dist/web/transport-stream.js +204 -0
  402. package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
  403. package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
  404. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
  405. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
  406. package/dist/web-client/assets/fraunces-latin-ext-wght-normal-Ca2vKHc0.woff2 +0 -0
  407. package/dist/web-client/assets/fraunces-latin-wght-normal-ukD16Tqj.woff2 +0 -0
  408. package/dist/web-client/assets/fraunces-vietnamese-wght-normal-CnvboYUG.woff2 +0 -0
  409. package/dist/web-client/assets/index-BZUxTkv5.css +2 -0
  410. package/dist/web-client/assets/index-D36PNBj4.js +80 -0
  411. package/dist/web-client/assets/instrument-sans-latin-ext-wght-normal-B5bTHO_g.woff2 +0 -0
  412. package/dist/web-client/assets/instrument-sans-latin-wght-normal-BbzFLZTg.woff2 +0 -0
  413. package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
  414. package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
  415. package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
  416. package/dist/web-client/index.html +3 -2
  417. package/package.json +32 -10
  418. package/dist/core/__tests__/error-stall-recycle.test.js +0 -141
  419. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +0 -57
  420. package/dist/core/skill-sync/builtins.js +0 -112
  421. package/dist/core/skill-sync/claude-plugins.d.ts +0 -23
  422. package/dist/core/skill-sync/claude-plugins.js +0 -71
  423. package/dist/core/skill-sync/engine.d.ts +0 -42
  424. package/dist/core/skill-sync/engine.js +0 -633
  425. package/dist/core/skill-sync/manifest.d.ts +0 -64
  426. package/dist/core/skill-sync/manifest.js +0 -181
  427. package/dist/core/skill-sync/profile.d.ts +0 -76
  428. package/dist/core/skill-sync/profile.js +0 -173
  429. package/dist/core/skill-sync/snapshot.d.ts +0 -57
  430. package/dist/core/skill-sync/snapshot.js +0 -120
  431. package/dist/pi-extensions/canvas-commands.d.ts +0 -37
  432. package/dist/pi-extensions/canvas-commands.js +0 -113
  433. package/dist/pi-extensions/canvas-resume.d.ts +0 -21
  434. package/dist/pi-extensions/canvas-resume.js +0 -83
  435. package/dist/pi-extensions/canvas-view.d.ts +0 -21
  436. package/dist/pi-extensions/canvas-view.js +0 -76
  437. package/dist/web-client/assets/index-BUvQb4hR.css +0 -2
  438. package/dist/web-client/assets/index-ClLQXYAE.js +0 -10
  439. /package/dist/{core/__tests__/error-stall-recycle.test.d.ts → clients/attach/__tests__/autocomplete-and-bash-mode.test.d.ts} +0 -0
  440. /package/dist/{core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts → clients/attach/__tests__/bash-bang-routing.test.d.ts} +0 -0
@@ -1,15 +1,22 @@
1
- // bearings.ts — the boot-intro prose (the <crtr-identity> assertion + the
2
- // <crtr-context> framing), shared by the paths that deliver it so they can
3
- // never drift:
1
+ // bearings.ts — the boot-intro prose (the <crtr-bearings> orientation block +
2
+ // the <memory kind="knowledge"> catalog that rides beside it), shared by the
3
+ // paths that deliver it so they can never drift:
4
4
  //
5
5
  // • the context-intro pi-extension injects buildContextBearings() as the
6
- // node's first session message in every brand-new chat. It opens with a
7
- // <crtr-identity> block (buildIdentityAssertion) that names the node and,
6
+ // node's first session message in every brand-new chat. The <crtr-bearings>
7
+ // block opens with the identity assertion (buildIdentityAssertion) that
8
+ // names the node (id, kind, mode), then a `## Your place in the canvas`
9
+ // mini-map (ancestry trunk up + immediate children with statuses, via
10
+ // buildGraphMap) and a `## Your context directory` note; identity leads,
8
11
  // ONLY for a fork, disowns the source's copied first-person narrative as
9
12
  // inherited context — the fix for the `--fork-from` bug where a fork copies
10
13
  // the source's whole conversation and then impersonates it. A non-fork
11
14
  // node's bearings are its FIRST entry, so there is nothing earlier to
12
- // disown; it gets only the declarative identity line;
15
+ // disown; it gets only the declarative identity line. The message also
16
+ // carries the <project_context> block (buildProjectContextBlock) — the
17
+ // AGENTS.md/CLAUDE.md project instructions, moved OUT of the system prompt
18
+ // (pi's copy is suppressed via noContextFiles in broker.ts) so they ride
19
+ // this user message instead;
13
20
  // • promote.ts folds orchestratorContextNote() into the promotion guidance
14
21
  // dump, so a node that becomes an orchestrator MID-LIFE gets the
15
22
  // orchestrator framing it never received at spawn — it spawned as a base
@@ -19,21 +26,186 @@
19
26
  // one place other nodes on the canvas can read from, so it is for documents
20
27
  // worth a shared reference, NOT a task tracker, and NOT a "future memory-wiped
21
28
  // you" stash (a terminal worker has no future cycle — that framing only makes
22
- // sense once a node is a resident orchestrator). The `<knowledge>` block
23
- // (substrate knowledge docs + node-local docs) rides into the context message.
29
+ // sense once a node is a resident orchestrator). The `<memory kind="knowledge">`
30
+ // block (substrate knowledge docs + node-local docs) rides as a SIBLING of
31
+ // <crtr-bearings> — never nested under the context dir, which would imply the
32
+ // catalog belongs to that one directory rather than spanning all memory scopes.
24
33
  //
25
34
  // Orchestrator addendum (gated on orchestrator MODE): the dir ALSO survives
26
35
  // refresh cycles, so it is where a future cycle of the orchestrator resumes.
27
36
  // This across-cycles note is the ONE thing a terminal worker's bearings drop.
28
- import { contextDir, getNode, fullName } from '../canvas/index.js';
37
+ import { contextDir, getNode, fullName, subscriptionsOf, } from '../canvas/index.js';
38
+ import { execSync } from 'node:child_process';
39
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
40
+ import { homedir } from 'node:os';
41
+ import { join, resolve } from 'node:path';
29
42
  import { cadenceDisplay } from '../wake.js';
30
43
  import { renderKnowledgeBlock } from '../substrate/index.js';
31
- /** Base framing — present for every node. No path baked in: the caller carries
32
- * the dir in the `<crtr-context dir="…">` attribute. */
33
- export const BASE_CONTEXT_NOTE = 'This is your context directory durable scratch space on disk, and the one place the other ' +
34
- 'nodes on the canvas can read from. Put documents here that you want to share by reference ' +
35
- 'instead of re-explaining them in a prompt: specs, designs, findings, notes worth pointing a ' +
36
- 'sibling, child, or parent at. It is a shared document store, not a task tracker.';
44
+ // ---------------------------------------------------------------------------
45
+ // Project context (<project_context>) the AGENTS.md/CLAUDE.md files pi would
46
+ // otherwise inject into its SYSTEM PROMPT, rendered here so they ride the
47
+ // first-message bearings instead (pi's copy is suppressed via
48
+ // resourceLoaderOptions.noContextFiles in broker.ts). We re-implement pi's
49
+ // loadProjectContextFiles + getAgentDir (resource-loader.js / config.js) rather
50
+ // than IMPORT pi: bearings.ts is statically imported by the thin daemon (crtrd,
51
+ // for wakeOriginFrom), so a static @earendil-works import would pull the whole
52
+ // pi engine into the supervisor. The discovery is a stable convention + pure fs.
53
+ // ---------------------------------------------------------------------------
54
+ /** pi's getAgentDir(): the global agent config dir holding a user-wide context
55
+ * file. Honors PI_CODING_AGENT_DIR (tilde-expanded), else ~/.pi/agent (pi's
56
+ * piConfig.configDir is ".pi"). */
57
+ function piAgentDir() {
58
+ const env = process.env['PI_CODING_AGENT_DIR'];
59
+ if (env !== undefined && env !== '') {
60
+ return env.startsWith('~') ? join(homedir(), env.slice(1)) : env;
61
+ }
62
+ return join(homedir(), '.pi', 'agent');
63
+ }
64
+ /** Per-dir context-file candidates, in pi's precedence order (first match wins). */
65
+ const CONTEXT_FILE_CANDIDATES = ['AGENTS.md', 'AGENTS.MD', 'CLAUDE.md', 'CLAUDE.MD'];
66
+ function loadContextFileFromDir(dir) {
67
+ for (const name of CONTEXT_FILE_CANDIDATES) {
68
+ const p = join(dir, name);
69
+ if (existsSync(p)) {
70
+ try {
71
+ return { path: p, content: readFileSync(p, 'utf8') };
72
+ }
73
+ catch {
74
+ // Unreadable candidate — skip, mirroring pi (best-effort).
75
+ }
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ /** Mirror of pi's loadProjectContextFiles: the global agent-dir file first, then
81
+ * every AGENTS.md/CLAUDE.md up the cwd's ancestry, ordered root→cwd (so the
82
+ * most-specific project file reads last). Deduped by absolute path. */
83
+ function loadProjectContextFiles(cwd) {
84
+ const files = [];
85
+ const seen = new Set();
86
+ const global = loadContextFileFromDir(piAgentDir());
87
+ if (global !== null) {
88
+ files.push(global);
89
+ seen.add(global.path);
90
+ }
91
+ const ancestors = [];
92
+ let dir = resolve(cwd);
93
+ const root = resolve('/');
94
+ for (;;) {
95
+ const f = loadContextFileFromDir(dir);
96
+ if (f !== null && !seen.has(f.path)) {
97
+ ancestors.unshift(f);
98
+ seen.add(f.path);
99
+ }
100
+ if (dir === root)
101
+ break;
102
+ const parent = resolve(dir, '..');
103
+ if (parent === dir)
104
+ break;
105
+ dir = parent;
106
+ }
107
+ files.push(...ancestors);
108
+ return files;
109
+ }
110
+ function escapeAttribute(value) {
111
+ return value.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
112
+ }
113
+ function directoryListingLines(cwd) {
114
+ try {
115
+ const entries = readdirSync(cwd, { withFileTypes: true });
116
+ const sorted = entries.sort((a, b) => {
117
+ if (a.isDirectory() !== b.isDirectory())
118
+ return a.isDirectory() ? -1 : 1;
119
+ return a.name.localeCompare(b.name);
120
+ });
121
+ const shown = sorted.slice(0, 50).map((entry) => `${entry.name}${entry.isDirectory() ? '/' : ''}`);
122
+ const hidden = sorted.length - shown.length;
123
+ return hidden > 0 ? [...shown, `[+${hidden} more]`] : shown;
124
+ }
125
+ catch {
126
+ return ['Directory listing: unavailable (cwd missing or unreadable).'];
127
+ }
128
+ }
129
+ function gitSnapshot(cwd) {
130
+ try {
131
+ execSync('git rev-parse --is-inside-work-tree', { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
132
+ }
133
+ catch {
134
+ return { lines: ['Git: not a git repository.'] };
135
+ }
136
+ const branch = runGit(cwd, 'git branch --show-current') || runGit(cwd, 'git rev-parse --abbrev-ref HEAD') || 'HEAD';
137
+ const sha = runGit(cwd, 'git rev-parse --short HEAD') || 'unknown';
138
+ const statusCount = runGit(cwd, 'git status --porcelain')
139
+ .split('\n')
140
+ .filter((line) => line !== '').length;
141
+ const worktreeLines = runGit(cwd, 'git worktree list --porcelain').split('\n');
142
+ const worktrees = parseWorktrees(worktreeLines);
143
+ const dirty = statusCount === 0 ? 'clean' : `${statusCount} uncommitted change${statusCount === 1 ? '' : 's'}`;
144
+ const summary = `Git: ${branch} @ ${sha}; ${dirty}; ${worktrees.length} worktree${worktrees.length === 1 ? '' : 's'}.`;
145
+ const worktreeSummary = worktrees.length === 0
146
+ ? 'Worktrees: none.'
147
+ : `Worktrees: ${worktrees.map((w) => `${w.path} (${w.branch})`).join(', ')}`;
148
+ return { lines: [summary, worktreeSummary] };
149
+ }
150
+ function runGit(cwd, command) {
151
+ try {
152
+ return execSync(command, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
153
+ }
154
+ catch {
155
+ return '';
156
+ }
157
+ }
158
+ function parseWorktrees(lines) {
159
+ const worktrees = [];
160
+ let cur = {};
161
+ for (const line of lines) {
162
+ if (line.startsWith('worktree ')) {
163
+ if (cur.path !== undefined) {
164
+ worktrees.push({ path: cur.path, branch: cur.branch ?? 'detached HEAD' });
165
+ }
166
+ cur = { path: line.slice('worktree '.length) };
167
+ }
168
+ else if (line.startsWith('branch ')) {
169
+ cur.branch = line.slice('branch '.length).replace(/^refs\/heads\//, '');
170
+ }
171
+ }
172
+ if (cur.path !== undefined) {
173
+ worktrees.push({ path: cur.path, branch: cur.branch ?? 'detached HEAD' });
174
+ }
175
+ return worktrees;
176
+ }
177
+ /** The `<project_context>` block for the files discovered from `cwd`, plus the
178
+ * cwd/git environment snapshot that now rides at the end of the wrapper.
179
+ * Always emits the wrapper because the environment snapshot is always present
180
+ * even when no project instructions exist. Exported for testing. */
181
+ export function buildProjectContextBlock(cwd) {
182
+ const files = loadProjectContextFiles(cwd);
183
+ const envLines = directoryListingLines(cwd);
184
+ const git = gitSnapshot(cwd);
185
+ let out = '<project_context>\n\nProject-specific instructions and guidelines:\n\n';
186
+ for (const { path, content } of files) {
187
+ out += `<project_instructions path="${path}">\n${content}\n</project_instructions>\n\n`;
188
+ }
189
+ out += `<environment cwd="${escapeAttribute(cwd)}">\n`;
190
+ out += `Directory:\n${envLines.map((line) => ` ${line}`).join('\n')}\n`;
191
+ out += `${git.lines.map((line) => `${line}`).join('\n')}\n`;
192
+ out += '</environment>\n</project_context>';
193
+ return out;
194
+ }
195
+ /** The context-directory note — names the path INLINE (no XML attribute, so it
196
+ * never scopes a sibling block) and frames the dir as durable, shared scratch.
197
+ * Present for every node, rendered as the `## Your context directory`
198
+ * subsection of <crtr-bearings>. */
199
+ export function contextDirNote(nodeId) {
200
+ return (`Your context directory is \`${contextDir(nodeId)}\` (also in the env as \`$CRTR_CONTEXT_DIR\`) — ` +
201
+ 'durable scratch space on disk, and the one place the other nodes on the canvas can read from. ' +
202
+ 'Put documents here that you want to share by reference instead of re-explaining them in a ' +
203
+ 'prompt: specs, designs, findings, notes worth pointing a sibling, child, or parent at. It is a ' +
204
+ 'shared document store, not a task tracker. **Address it by absolute path** — write artifacts as ' +
205
+ '`$CRTR_CONTEXT_DIR/<name>.md` (or the full path above). Your working dir is the project, NOT ' +
206
+ 'this directory, so a bare relative `context/...` lands in the repo, not here — and other nodes ' +
207
+ 'can only read what is actually here. When you report a file, report its absolute path.');
208
+ }
37
209
  /** Orchestrator-only framing: a resident orchestrator survives refresh cycles,
38
210
  * so its context dir is also where a future cycle of itself resumes the work.
39
211
  * Used inside the bearings block AND in the promotion guidance dump, so a
@@ -43,39 +215,121 @@ export function orchestratorContextNote(nodeId) {
43
215
  `also where a future cycle of you resumes the work — keep the working notes and decisions a ` +
44
216
  `refreshed you would need there, alongside the docs you share with the nodes you spawn.`);
45
217
  }
218
+ // ---------------------------------------------------------------------------
219
+ // Graph mini-map — the node's place in the canvas, rendered into the identity
220
+ // block so a node boots oriented: who is above it (its ancestry trunk, root
221
+ // first) and who is directly below it (its immediate children + their statuses).
222
+ // Not the full subtree — just the load-bearing spine up and one level down.
223
+ // ---------------------------------------------------------------------------
224
+ /** Live-first sibling ordering, so running children surface above finished ones. */
225
+ function statusRank(status) {
226
+ switch (status) {
227
+ case 'active': return 0;
228
+ case 'idle': return 1;
229
+ case 'done': return 2;
230
+ case 'canceled': return 3;
231
+ case 'dead': return 4;
232
+ default: return 5;
233
+ }
234
+ }
235
+ /** One relative's line in the map: `<id> — <kind> · <status>`, plus the node's
236
+ * task description when it carries one (orientation: what that relative is for). */
237
+ function relativeLabel(meta) {
238
+ const desc = fullName(meta);
239
+ const descPart = desc !== '' && desc !== meta.kind && desc !== meta.name ? ` — ${desc}` : '';
240
+ return `${meta.node_id} (${meta.kind} · ${meta.status})${descPart}`;
241
+ }
242
+ /** Ancestry trunk from the root DOWN to (but excluding) `nodeId`, climbing the
243
+ * spine `parent` edge. Cycle-guarded. Root first. */
244
+ function ancestorTrunk(nodeId) {
245
+ const trunk = [];
246
+ const seen = new Set([nodeId]);
247
+ let cur = getNode(nodeId)?.parent ?? null;
248
+ while (cur !== null && cur !== '' && !seen.has(cur)) {
249
+ seen.add(cur);
250
+ const m = getNode(cur);
251
+ if (m === null)
252
+ break;
253
+ trunk.unshift(m);
254
+ cur = m.parent ?? null;
255
+ }
256
+ return trunk;
257
+ }
258
+ /** Most children listed in the mini-map before the rest collapse to `+N more`. */
259
+ const MAX_CHILDREN_SHOWN = 5;
260
+ /** The node's immediate children — the nodes it subscribes to (its reports) —
261
+ * with human-ask control-plane nodes dropped, sorted live-first. */
262
+ function childNodes(nodeId) {
263
+ return subscriptionsOf(nodeId)
264
+ .map((s) => getNode(s.node_id))
265
+ .filter((m) => m !== null && m.kind !== 'human')
266
+ .sort((a, b) => statusRank(a.status) - statusRank(b.status));
267
+ }
268
+ /** The graph mini-map: the ancestry trunk (root first), then this node marked
269
+ * `● you`, then its immediate children. Returns '' for a lone root with no
270
+ * children (nothing to map). Exported for testing. */
271
+ export function buildGraphMap(nodeId) {
272
+ const meta = getNode(nodeId);
273
+ if (meta === null)
274
+ return '';
275
+ const trunk = ancestorTrunk(nodeId);
276
+ const children = childNodes(nodeId);
277
+ if (trunk.length === 0 && children.length === 0)
278
+ return '';
279
+ const indent = (depth) => ' '.repeat(depth);
280
+ const lines = [
281
+ 'Your place in the canvas graph (ancestry above you, your direct children below):',
282
+ ];
283
+ trunk.forEach((m, i) => {
284
+ lines.push(`${indent(i)}${i === 0 ? '' : '└ '}${relativeLabel(m)}`);
285
+ });
286
+ const selfDepth = trunk.length;
287
+ lines.push(`${indent(selfDepth)}${selfDepth === 0 ? '' : '└ '}● you: ${nodeId} (${meta.kind}, ${meta.mode})`);
288
+ // Cap the child list so a wide fan-out can't flood the boot context. Children
289
+ // are sorted live-first, so the shown slice favors active nodes; the rest
290
+ // collapse to a `+N more` tail (active-first ordering means anything elided is
291
+ // the most-finished work).
292
+ const shown = children.slice(0, MAX_CHILDREN_SHOWN);
293
+ const hidden = children.length - shown.length;
294
+ shown.forEach((m, i) => {
295
+ const last = i === shown.length - 1 && hidden === 0;
296
+ lines.push(`${indent(selfDepth + 1)}${last ? '└ ' : '├ '}${relativeLabel(m)}`);
297
+ });
298
+ if (hidden > 0) {
299
+ lines.push(`${indent(selfDepth + 1)}└ +${hidden} more`);
300
+ }
301
+ return lines.join('\n');
302
+ }
46
303
  /** The IDENTITY assertion that opens every boot intro — the load-bearing fix
47
304
  * for the `--fork-from` impersonation bug. A fork copies the SOURCE node's
48
305
  * entire first-person conversation into its own session, so without an explicit
49
306
  * re-assertion the forked agent reads that copied narrative as its own and
50
307
  * impersonates the source (it kept "monitoring itself" as a phantom child).
51
- * This block names the node unambiguously. ONLY when the node IS a fork does it
52
- * additionally name the source AND disown the copied first-person narrative as
53
- * inherited reference material a non-fork node's bearings are its first session
54
- * entry, so there is no earlier narrative to disown (emitting a disown line there
55
- * is dead weight that reads as a contradiction with no referent). Always the FIRST
56
- * thing the node reads. Exported for testing. */
308
+ * These lines name the node unambiguously and lead the <crtr-bearings> block
309
+ * (no wrapper of their own identity is the first prose the model reads). ONLY
310
+ * when the node IS a fork do they additionally name the source AND disown the
311
+ * copied first-person narrative as inherited reference material a non-fork
312
+ * node's bearings are its first session entry, so there is no earlier narrative
313
+ * to disown (emitting a disown line there is dead weight that reads as a
314
+ * contradiction with no referent). Also prepended to a fork's kickoff prompt in
315
+ * spawn.ts. Exported for testing. */
57
316
  export function buildIdentityAssertion(nodeId) {
58
317
  const meta = getNode(nodeId);
59
- const name = meta?.name ?? nodeId;
60
318
  const kind = meta?.kind ?? 'general';
61
319
  const mode = meta?.mode ?? 'base';
62
- const lines = [
63
- '<crtr-identity>',
64
- `You are node ${nodeId} — name "${name}", kind ${kind}, mode ${mode}.`,
65
- ];
320
+ const lines = [`You are node ${nodeId} — kind ${kind}, mode ${mode}.`];
66
321
  const forkFrom = meta?.fork_from;
67
322
  if (forkFrom !== undefined && forkFrom !== null && forkFrom !== '') {
68
323
  // Name the source: a known node id gets its human label; a raw path/uuid
69
324
  // passes through as-is.
70
325
  const src = getNode(forkFrom);
71
326
  const sourceLabel = src !== null ? `${forkFrom} ("${fullName(src)}")` : forkFrom;
72
- lines.push(`You are a FORK of ${sourceLabel}: at spawn pi COPIED that node's conversation into your ` +
327
+ lines.push('', `You are a FORK of ${sourceLabel}: at spawn pi COPIED that node's conversation into your ` +
73
328
  `session as a starting point. You are NOT ${sourceLabel}. Everything earlier in this ` +
74
329
  'conversation is THEIR first-person history — inherited reference material, not your own ' +
75
330
  'past. Do not speak or act as them, do not continue their task as if it were yours, and do ' +
76
331
  'not "monitor yourself" as though you were a child they spawned.');
77
332
  }
78
- lines.push('</crtr-identity>');
79
333
  return lines.join('\n');
80
334
  }
81
335
  /** Build a WakeOrigin from a fired wakeup row, resolving the armer's display
@@ -141,25 +395,32 @@ export function buildWakeBearings(origin) {
141
395
  }
142
396
  return `<crtr-wake>\n${body}\n</crtr-wake>`;
143
397
  }
144
- /** The full boot intro: the IDENTITY assertion (always first, so it overrides
145
- * any copied-in persona) followed by the `<crtr-context>` bearings block. Base
146
- * framing rides for EVERY node; the across-cycles context-dir note is added
147
- * ONLY for an orchestrator (by mode) the one node whose dir a future cycle
148
- * resumes from. The `<knowledge>` block carries the substrate knowledge docs
149
- * + node-local docs. */
398
+ /** The full boot intro, three top-level sections:
399
+ *
400
+ * 1. `<crtr-bearings>` the orienting facts about THIS node: the identity
401
+ * assertion (always first, so it overrides any copied-in persona), then a
402
+ * `## Your place in the canvas` graph map and a `## Your context directory`
403
+ * note. The across-cycles context-dir framing is added ONLY for an
404
+ * orchestrator (by mode) — the one node whose dir a future cycle resumes
405
+ * from.
406
+ * 2. `<memory kind="knowledge">` — the consultable catalog, a SIBLING of the
407
+ * bearings (never nested under the context dir). Dropped when empty.
408
+ * 3. `<project_context>` — the AGENTS.md/CLAUDE.md instructions + the cwd/git
409
+ * environment snapshot, moved OUT of the system prompt (pi's copy is
410
+ * suppressed via noContextFiles in broker.ts) so it rides this message. */
150
411
  export function buildContextBearings(nodeId) {
151
- const identity = buildIdentityAssertion(nodeId);
152
- const dir = contextDir(nodeId);
153
412
  const node = getNode(nodeId);
154
- const parts = [BASE_CONTEXT_NOTE];
413
+ const bearings = ['<crtr-bearings>', buildIdentityAssertion(nodeId)];
414
+ const map = buildGraphMap(nodeId);
415
+ if (map !== '')
416
+ bearings.push('', '## Your place in the canvas', map);
417
+ bearings.push('', '## Your context directory', contextDirNote(nodeId));
155
418
  // Orchestrator-only: the across-cycles framing (a terminal has no future cycle).
156
419
  if (node?.mode === 'orchestrator')
157
- parts.push(orchestratorContextNote(nodeId));
158
- // The substrate knowledge block: eligible `knowledge` docs at their
159
- // system-prompt rung + node-local memory docs; dropped (returns '') when
160
- // nothing is eligible.
420
+ bearings.push('', orchestratorContextNote(nodeId));
421
+ bearings.push('</crtr-bearings>');
422
+ // The consultable catalog rides BESIDE the bearings, not inside them.
161
423
  const knowledge = renderKnowledgeBlock(nodeId);
162
- if (knowledge !== '')
163
- parts.push(knowledge);
164
- return `${identity}\n<crtr-context dir="${dir}">\n${parts.join('\n')}\n</crtr-context>`;
424
+ const projectCtx = node?.cwd !== undefined ? buildProjectContextBlock(node.cwd) : '';
425
+ return [bearings.join('\n'), knowledge, projectCtx].filter((s) => s !== '').join('\n');
165
426
  }
@@ -3,6 +3,8 @@
3
3
  * to the installed node, shared across every canvas home. */
4
4
  export declare function brandedHostDir(): string;
5
5
  export declare function brandedHostBin(): string;
6
+ export declare function signBrandedHostArtifacts(binPath: string, libnodePath: string | null, sign?: (path: string) => void): void;
7
+ export declare function brandedHostWorks(binPath: string): boolean;
6
8
  /** Ensure the branded host binary exists and matches the live node; return its
7
9
  * absolute path. Idempotent and self-healing. Throws on a genuine build failure
8
10
  * (disk full / permissions) — branding is load-bearing for FDA, so a failure is
@@ -11,6 +13,6 @@ export declare function ensureBrandedHost(): string;
11
13
  /** The path the engine (broker / daemon) should be launched from. On macOS in a
12
14
  * compiled (production) build this is the branded host; otherwise — non-darwin
13
15
  * (TCC is macOS-only), source/tsx (dev + the test suite: never copy 70 MB into
14
- * the real ~/.crouter), or an explicit `CRTR_BRANDED_HOST=0` opt-out it is the
15
- * live node. These are environment gates, not error fallbacks. */
16
+ * the real ~/.crouter), an explicit `CRTR_BRANDED_HOST=0` opt-out, or a copied
17
+ * host that macOS kills before it can execute JS — it is the live node. */
16
18
  export declare function hostExecPath(): string;
@@ -24,6 +24,7 @@
24
24
  import { copyFileSync, mkdirSync, existsSync, readFileSync, writeFileSync, chmodSync, readdirSync, renameSync, realpathSync, unlinkSync, } from 'node:fs';
25
25
  import { homedir } from 'node:os';
26
26
  import { dirname, join } from 'node:path';
27
+ import { spawnSync } from 'node:child_process';
27
28
  import { CRTR_DIR_NAME } from '../../types.js';
28
29
  /** The filename the FDA / TCC entry is shown under. */
29
30
  const BRANDED_BIN_NAME = 'crouter';
@@ -71,6 +72,61 @@ function readMarker() {
71
72
  return null;
72
73
  }
73
74
  }
75
+ /** Sign a copied branded-host artifact with the Apple Development identity.
76
+ * macOS keys FDA grants on the Mach-O cdhash, so ad-hoc signing loses grants
77
+ * after each rebuild. Stable signing preserves them. Non-fatal — if signing
78
+ * fails (no certificate, non-macOS, etc), return silently. */
79
+ function signBrandedHost(binPath) {
80
+ if (process.platform !== 'darwin')
81
+ return;
82
+ try {
83
+ const res = spawnSync('codesign', [
84
+ '-s',
85
+ 'Apple Development: Silas Rhyneer (8W9CF7WS32)',
86
+ '--deep',
87
+ '--force',
88
+ binPath,
89
+ ], { stdio: ['pipe', 'pipe', 'pipe'] });
90
+ if (res.status !== 0) {
91
+ const stderr = (res.stderr ?? '').toString().trim();
92
+ if (stderr && !stderr.includes('valid on disk')) {
93
+ console.debug(`[crouter] codesign failed (expected on some systems): ${stderr}`);
94
+ }
95
+ }
96
+ }
97
+ catch {
98
+ // codesign not found or other spawn error — non-fatal, continue.
99
+ }
100
+ }
101
+ export function signBrandedHostArtifacts(binPath, libnodePath, sign = signBrandedHost) {
102
+ if (libnodePath !== null)
103
+ sign(libnodePath);
104
+ sign(binPath);
105
+ }
106
+ let brandedHostWarningShown = false;
107
+ export function brandedHostWorks(binPath) {
108
+ try {
109
+ const res = spawnSync(binPath, ['-e', ''], {
110
+ stdio: 'ignore',
111
+ timeout: 2_000,
112
+ });
113
+ return res.status === 0;
114
+ }
115
+ catch {
116
+ return false;
117
+ }
118
+ }
119
+ function warnBrandedHostFallback(binPath) {
120
+ if (brandedHostWarningShown)
121
+ return;
122
+ brandedHostWarningShown = true;
123
+ try {
124
+ process.stderr.write(`[crouter] branded host ${binPath} failed its startup check; using ${process.execPath} for broker/daemon processes.\n`);
125
+ }
126
+ catch {
127
+ /* best effort */
128
+ }
129
+ }
74
130
  /** Ensure the branded host binary exists and matches the live node; return its
75
131
  * absolute path. Idempotent and self-healing. Throws on a genuine build failure
76
132
  * (disk full / permissions) — branding is load-bearing for FDA, so a failure is
@@ -89,6 +145,7 @@ export function ensureBrandedHost() {
89
145
  const libnodeName = libnodeSrc !== null ? libnodeSrc.split('/').pop() : null;
90
146
  const fresh = existsSync(dst) &&
91
147
  marker !== null &&
148
+ marker.version === 2 &&
92
149
  marker.source === src &&
93
150
  marker.libnode === libnodeName &&
94
151
  (libnodeName === null || existsSync(join(brandedHostDir(), libnodeName)));
@@ -108,14 +165,15 @@ export function ensureBrandedHost() {
108
165
  atomicCopy(libnodeSrc, join(brandedHostDir(), libnodeName));
109
166
  }
110
167
  atomicCopy(src, dst, 0o755);
111
- writeFileSync(markerPath(), JSON.stringify({ source: src, libnode: libnodeName }));
168
+ signBrandedHostArtifacts(dst, libnodeName !== null ? join(brandedHostDir(), libnodeName) : null);
169
+ writeFileSync(markerPath(), JSON.stringify({ version: 2, source: src, libnode: libnodeName }));
112
170
  return dst;
113
171
  }
114
172
  /** The path the engine (broker / daemon) should be launched from. On macOS in a
115
173
  * compiled (production) build this is the branded host; otherwise — non-darwin
116
174
  * (TCC is macOS-only), source/tsx (dev + the test suite: never copy 70 MB into
117
- * the real ~/.crouter), or an explicit `CRTR_BRANDED_HOST=0` opt-out it is the
118
- * live node. These are environment gates, not error fallbacks. */
175
+ * the real ~/.crouter), an explicit `CRTR_BRANDED_HOST=0` opt-out, or a copied
176
+ * host that macOS kills before it can execute JS — it is the live node. */
119
177
  export function hostExecPath() {
120
178
  if (process.env['CRTR_BRANDED_HOST'] === '0')
121
179
  return process.execPath;
@@ -123,5 +181,9 @@ export function hostExecPath() {
123
181
  return process.execPath;
124
182
  if (import.meta.url.endsWith('.ts'))
125
183
  return process.execPath;
126
- return ensureBrandedHost();
184
+ const host = ensureBrandedHost();
185
+ if (brandedHostWorks(host))
186
+ return host;
187
+ warnBrandedHostFallback(host);
188
+ return process.execPath;
127
189
  }
@@ -128,6 +128,17 @@ export interface FollowUpFrame {
128
128
  export interface AbortFrame {
129
129
  type: 'abort';
130
130
  }
131
+ /** Run a `!` bash command — controller only. Maps to `session.executeBash()`,
132
+ * which runs the command, records a `bashExecution` message in context, and
133
+ * starts NO agent turn (pi's interactive `!`/`!!` semantics). `command` is the
134
+ * text AFTER the leading `!`/`!!`; `excludeFromContext` is the `!!` form (output
135
+ * shown but withheld from the LLM). The broker streams the result back as
136
+ * `bash_start`/`bash_output`/`bash_end` frames. */
137
+ export interface BashFrame {
138
+ type: 'bash';
139
+ command: string;
140
+ excludeFromContext?: boolean;
141
+ }
131
142
  /** Controller arbitration (§5.3). */
132
143
  export interface RequestControlFrame {
133
144
  type: 'request_control';
@@ -284,11 +295,15 @@ export interface ShareFrame {
284
295
  type: 'share';
285
296
  }
286
297
  /** Reload credentials + refresh model registry after a viewer-side auth change.
287
- * Controller-only. Broker handler: services.authStorage.reload() + services.modelRegistry.refresh(). */
298
+ * Open to any client reload_auth is an idempotent local re-read that doesn't
299
+ * steer the conversation, so the daemon's canvas-wide fan (one /login → every
300
+ * live broker) can trigger it without claiming controller and demoting an
301
+ * attached human. Broker handler: services.authStorage.reload() +
302
+ * services.modelRegistry.refresh(). */
288
303
  export interface ReloadAuthFrame {
289
304
  type: 'reload_auth';
290
305
  }
291
- export type ClientToBroker = HelloFrame | PromptFrame | SteerFrame | FollowUpFrame | AbortFrame | RequestControlFrame | ReleaseControlFrame | ByeFrame | ShutdownFrame | SetModelFrame | CycleModelFrame | CycleThinkingFrame | SetThinkingLevelFrame | DequeueFrame | SetAutoRetryFrame | SetAutoCompactionFrame | CompactFrame | NewSessionFrame | SwitchSessionFrame | ForkFrame | SetSessionNameFrame | GetCommandsFrame | NavigateTreeFrame | ReloadFrame | ExportFrame | ListModelsFrame | ListSessionsFrame | GetTreeFrame | GetSettingsFrame | ListScopedModelsFrame | ExtensionUIResponseFrame | CloneFrame | ShareFrame | ReloadAuthFrame;
306
+ export type ClientToBroker = HelloFrame | PromptFrame | SteerFrame | FollowUpFrame | AbortFrame | BashFrame | RequestControlFrame | ReleaseControlFrame | ByeFrame | ShutdownFrame | SetModelFrame | CycleModelFrame | CycleThinkingFrame | SetThinkingLevelFrame | DequeueFrame | SetAutoRetryFrame | SetAutoCompactionFrame | CompactFrame | NewSessionFrame | SwitchSessionFrame | ForkFrame | SetSessionNameFrame | GetCommandsFrame | NavigateTreeFrame | ReloadFrame | ExportFrame | ListModelsFrame | ListSessionsFrame | GetTreeFrame | GetSettingsFrame | ListScopedModelsFrame | ExtensionUIResponseFrame | CloneFrame | ShareFrame | ReloadAuthFrame;
292
307
  export interface WelcomeFrame {
293
308
  type: 'welcome';
294
309
  snapshot: BrokerSnapshot;
@@ -335,6 +350,26 @@ export interface AckFrame {
335
350
  ok: boolean;
336
351
  detail?: string;
337
352
  }
353
+ /** A `!` run has begun — viewers create the bash component. */
354
+ export interface BashStartFrame {
355
+ type: 'bash_start';
356
+ command: string;
357
+ excludeFromContext?: boolean;
358
+ }
359
+ /** A streamed chunk of combined stdout+stderr for the in-flight `!` run. */
360
+ export interface BashOutputFrame {
361
+ type: 'bash_output';
362
+ chunk: string;
363
+ }
364
+ /** The `!` run finished — viewers mark the bash component complete. Mirrors
365
+ * `BashResult` minus the (already-streamed) `output`. */
366
+ export interface BashEndFrame {
367
+ type: 'bash_end';
368
+ exitCode: number | undefined;
369
+ cancelled: boolean;
370
+ truncated: boolean;
371
+ fullOutputPath?: string;
372
+ }
338
373
  /** `provider/id` model reference — the wire form of a current/selected model. */
339
374
  export interface WireModelRef {
340
375
  provider: string;
@@ -462,7 +497,7 @@ export type ExtensionUIRequestFrame = RpcExtensionUIRequest;
462
497
  /** Everything the broker can send. Live `AgentSessionEvent`s are relayed
463
498
  * verbatim (the broker adds nothing); the broker's own control frames carry
464
499
  * non-colliding `type` discriminants. */
465
- export type BrokerToClient = WelcomeFrame | ControlChangedFrame | ModelChangedFrame | ErrorFrame | AckFrame | BrokerDataFrame | DisplayStatusFrame | DisplayWidgetFrame | DisplayTitleFrame | ExtensionUIRequestFrame | AgentSessionEvent;
500
+ export type BrokerToClient = WelcomeFrame | ControlChangedFrame | ModelChangedFrame | ErrorFrame | AckFrame | BrokerDataFrame | DisplayStatusFrame | DisplayWidgetFrame | DisplayTitleFrame | BashStartFrame | BashOutputFrame | BashEndFrame | ExtensionUIRequestFrame | AgentSessionEvent;
466
501
  /** Encode one frame as a single newline-terminated JSON line. */
467
502
  export declare function encodeFrame(frame: ClientToBroker | BrokerToClient): string;
468
503
  /** Byte bounds for a {@link FrameDecoder} (C5). */