@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
@@ -0,0 +1,342 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ import { general } from '../../core/errors.js';
4
+ import { getHome, putHome, updateHome } from '../../core/hearth/registry.js';
5
+ import { nowIso } from '../../core/fs-utils.js';
6
+ const LOCK_STALE_MS = 2 * 60_000;
7
+ const DEFAULT_VERSION = 1;
8
+ const tenantLocks = new Map();
9
+ const tenantRuntimes = new Map();
10
+ function ensureParentDir(path) {
11
+ mkdirSync(dirname(path), { recursive: true });
12
+ }
13
+ function atomicWriteJson(path, value) {
14
+ ensureParentDir(path);
15
+ const tmp = `${path}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
16
+ writeFileSync(tmp, JSON.stringify(value, null, 2) + '\n', { encoding: 'utf8', mode: 0o600 });
17
+ try {
18
+ renameSync(tmp, path);
19
+ }
20
+ catch (error) {
21
+ try {
22
+ rmSync(tmp, { force: true });
23
+ }
24
+ catch {
25
+ /* ignore */
26
+ }
27
+ throw error;
28
+ }
29
+ }
30
+ function readJsonFile(path) {
31
+ return JSON.parse(readFileSync(path, 'utf8'));
32
+ }
33
+ function normalizeProxyState(value) {
34
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
35
+ throw general('invalid hearth proxy state file', { valueType: value === null ? 'null' : typeof value });
36
+ }
37
+ const obj = value;
38
+ const owner = obj.owner;
39
+ if (owner === null || typeof owner !== 'object' || Array.isArray(owner)) {
40
+ throw general('invalid hearth proxy state owner', { valueType: typeof owner });
41
+ }
42
+ const ownerObj = owner;
43
+ if (typeof ownerObj.ownerUserId !== 'string' || typeof ownerObj.defaultTenantId !== 'string' || typeof ownerObj.tokenHash !== 'string') {
44
+ throw general('invalid hearth proxy state owner fields', { owner });
45
+ }
46
+ const tenantsRaw = obj.tenants;
47
+ const tenants = {};
48
+ if (tenantsRaw !== undefined) {
49
+ if (tenantsRaw === null || typeof tenantsRaw !== 'object' || Array.isArray(tenantsRaw)) {
50
+ throw general('invalid hearth proxy tenants map', { tenantsRaw });
51
+ }
52
+ for (const [tenantId, tenant] of Object.entries(tenantsRaw)) {
53
+ if (tenant === null || typeof tenant !== 'object' || Array.isArray(tenant))
54
+ continue;
55
+ const draft = tenant;
56
+ if (typeof draft.tenantId !== 'string' || typeof draft.ownerUserId !== 'string' || typeof draft.m0RegistryPath !== 'string' || typeof draft.idleAfterMs !== 'number' || typeof draft.updatedAt !== 'string') {
57
+ continue;
58
+ }
59
+ tenants[tenantId] = {
60
+ tenantId: draft.tenantId,
61
+ ownerUserId: draft.ownerUserId,
62
+ m0RegistryPath: draft.m0RegistryPath,
63
+ idleAfterMs: draft.idleAfterMs,
64
+ lastActivityAt: typeof draft.lastActivityAt === 'string' ? draft.lastActivityAt : null,
65
+ lastWakeAt: typeof draft.lastWakeAt === 'string' ? draft.lastWakeAt : null,
66
+ lastPauseAt: typeof draft.lastPauseAt === 'string' ? draft.lastPauseAt : null,
67
+ updatedAt: draft.updatedAt,
68
+ };
69
+ }
70
+ }
71
+ return {
72
+ version: DEFAULT_VERSION,
73
+ owner: {
74
+ ownerUserId: ownerObj.ownerUserId,
75
+ defaultTenantId: ownerObj.defaultTenantId,
76
+ tokenHash: ownerObj.tokenHash,
77
+ createdAt: typeof ownerObj.createdAt === 'string' ? ownerObj.createdAt : nowIso(),
78
+ },
79
+ tenants,
80
+ };
81
+ }
82
+ export function loadProxyState(statePath) {
83
+ if (!existsSync(statePath))
84
+ return null;
85
+ return normalizeProxyState(readJsonFile(statePath));
86
+ }
87
+ export function saveProxyState(statePath, state) {
88
+ atomicWriteJson(statePath, state);
89
+ return state;
90
+ }
91
+ export function ensureProxyState(config) {
92
+ const existing = loadProxyState(config.statePath);
93
+ const now = nowIso();
94
+ const base = existing ?? {
95
+ version: DEFAULT_VERSION,
96
+ owner: {
97
+ ownerUserId: config.ownerUserId,
98
+ defaultTenantId: config.defaultTenantId,
99
+ tokenHash: config.ownerTokenHash,
100
+ createdAt: now,
101
+ },
102
+ tenants: {},
103
+ };
104
+ base.owner.ownerUserId = config.ownerUserId;
105
+ base.owner.defaultTenantId = config.defaultTenantId;
106
+ base.owner.tokenHash = config.ownerTokenHash;
107
+ if (base.owner.createdAt.trim() === '')
108
+ base.owner.createdAt = now;
109
+ base.tenants[config.defaultTenantId] = ensureTenantState(base.tenants[config.defaultTenantId], config, now);
110
+ return saveProxyState(config.statePath, base);
111
+ }
112
+ export function getTenantState(state, tenantId) {
113
+ return state.tenants[tenantId] ?? null;
114
+ }
115
+ function ensureTenantState(existing, config, now = nowIso()) {
116
+ return {
117
+ tenantId: existing?.tenantId ?? config.defaultTenantId,
118
+ ownerUserId: existing?.ownerUserId ?? config.ownerUserId,
119
+ m0RegistryPath: existing?.m0RegistryPath ?? config.m0RegistryPath,
120
+ idleAfterMs: existing?.idleAfterMs ?? config.idlePauseMs,
121
+ lastActivityAt: existing?.lastActivityAt ?? null,
122
+ lastWakeAt: existing?.lastWakeAt ?? null,
123
+ lastPauseAt: existing?.lastPauseAt ?? null,
124
+ updatedAt: now,
125
+ };
126
+ }
127
+ export function updateTenantState(config, tenantId, mutate) {
128
+ const state = ensureProxyState(config);
129
+ const current = state.tenants[tenantId] ?? ensureTenantState(undefined, config);
130
+ const draft = { ...current, tenantId, ownerUserId: config.ownerUserId, m0RegistryPath: config.m0RegistryPath, idleAfterMs: config.idlePauseMs };
131
+ const next = mutate(draft) ?? draft;
132
+ next.updatedAt = nowIso();
133
+ state.tenants[tenantId] = next;
134
+ return saveProxyState(config.statePath, state).tenants[tenantId];
135
+ }
136
+ export function touchTenantActivity(config, tenantId) {
137
+ return updateTenantState(config, tenantId, (tenant) => {
138
+ tenant.lastActivityAt = nowIso();
139
+ });
140
+ }
141
+ export function touchTenantWake(config, tenantId) {
142
+ return updateTenantState(config, tenantId, (tenant) => {
143
+ tenant.lastWakeAt = nowIso();
144
+ });
145
+ }
146
+ export function touchTenantPause(config, tenantId) {
147
+ return updateTenantState(config, tenantId, (tenant) => {
148
+ tenant.lastPauseAt = nowIso();
149
+ });
150
+ }
151
+ export function withTenantLock(tenantId, fn) {
152
+ const previous = tenantLocks.get(tenantId) ?? Promise.resolve();
153
+ let release;
154
+ const current = new Promise((resolve) => {
155
+ release = resolve;
156
+ });
157
+ const tail = previous.then(() => current, () => current);
158
+ tenantLocks.set(tenantId, tail);
159
+ return previous
160
+ .catch(() => undefined)
161
+ .then(() => Promise.resolve(fn()))
162
+ .finally(() => {
163
+ release();
164
+ if (tenantLocks.get(tenantId) === tail) {
165
+ tenantLocks.delete(tenantId);
166
+ }
167
+ });
168
+ }
169
+ function runtimeFor(tenantId) {
170
+ const existing = tenantRuntimes.get(tenantId);
171
+ if (existing !== undefined)
172
+ return existing;
173
+ const created = {
174
+ counts: { http: 0, ws: 0, wake: 0 },
175
+ idleDeadlineAt: null,
176
+ timer: null,
177
+ };
178
+ tenantRuntimes.set(tenantId, created);
179
+ return created;
180
+ }
181
+ function clearTimer(runtime) {
182
+ if (runtime.timer !== null) {
183
+ clearTimeout(runtime.timer);
184
+ runtime.timer = null;
185
+ }
186
+ runtime.idleDeadlineAt = null;
187
+ }
188
+ export function beginActivity(config, tenantId, kind) {
189
+ const runtime = runtimeFor(tenantId);
190
+ runtime.counts[kind] += 1;
191
+ clearTimer(runtime);
192
+ touchTenantActivity(config, tenantId);
193
+ return {
194
+ tenantId,
195
+ kind,
196
+ acquiredAt: nowIso(),
197
+ closed: false,
198
+ };
199
+ }
200
+ export function endActivity(handle) {
201
+ const runtime = runtimeFor(handle.tenantId);
202
+ if (!handle.closed) {
203
+ handle.closed = true;
204
+ runtime.counts[handle.kind] = Math.max(0, runtime.counts[handle.kind] - 1);
205
+ }
206
+ const total = runtime.counts.http + runtime.counts.ws + runtime.counts.wake;
207
+ return {
208
+ tenantId: handle.tenantId,
209
+ counts: { ...runtime.counts },
210
+ total,
211
+ idleDeadlineAt: runtime.idleDeadlineAt,
212
+ };
213
+ }
214
+ export function getTenantActivitySnapshot(tenantId) {
215
+ const runtime = runtimeFor(tenantId);
216
+ return {
217
+ tenantId,
218
+ counts: { ...runtime.counts },
219
+ total: runtime.counts.http + runtime.counts.ws + runtime.counts.wake,
220
+ idleDeadlineAt: runtime.idleDeadlineAt,
221
+ };
222
+ }
223
+ export function setTenantIdleTimer(tenantId, deadlineAt, timer) {
224
+ const runtime = runtimeFor(tenantId);
225
+ clearTimer(runtime);
226
+ runtime.idleDeadlineAt = deadlineAt;
227
+ runtime.timer = timer;
228
+ }
229
+ export function clearTenantIdleTimer(tenantId) {
230
+ clearTimer(runtimeFor(tenantId));
231
+ }
232
+ export function readTenantHome(config, tenantId) {
233
+ return getHome(config.m0RegistryPath, tenantId);
234
+ }
235
+ function mergeHomeStorage(home, m0Config, volumeId) {
236
+ const next = { ...home };
237
+ next.providerName = m0Config.providerName;
238
+ next.homeStorage = {
239
+ kind: 'volume',
240
+ durability: 'durable-volume',
241
+ longTermContract: true,
242
+ ownerMachineId: home.machineId,
243
+ guestHome: m0Config.guestHome,
244
+ volumeId,
245
+ mountPath: m0Config.guestHome,
246
+ };
247
+ return next;
248
+ }
249
+ export function ensureSeededM0Registry(config, m0Config) {
250
+ const existing = getHome(config.m0RegistryPath, config.defaultTenantId);
251
+ if (existing !== null) {
252
+ if (typeof existing.machineId !== 'string' || existing.machineId.trim() === '') {
253
+ throw general('hearth m0 registry is missing machineId — run the existing M0 provision/bootstrap flow before starting the wake proxy', {
254
+ tenantId: config.defaultTenantId,
255
+ registryPath: config.m0RegistryPath,
256
+ });
257
+ }
258
+ const updated = updateHome(config.m0RegistryPath, config.defaultTenantId, (home) => {
259
+ if (home.providerName !== m0Config.providerName)
260
+ home.providerName = m0Config.providerName;
261
+ if (!home.homeStorage || home.homeStorage.volumeId.trim() === '') {
262
+ if (config.seedHome === null) {
263
+ throw general('hearth m0 registry is missing homeStorage.volumeId and no seed home was provided', {
264
+ tenantId: config.defaultTenantId,
265
+ registryPath: config.m0RegistryPath,
266
+ });
267
+ }
268
+ home.homeStorage = mergeHomeStorage(home, m0Config, config.seedHome.volumeId).homeStorage;
269
+ }
270
+ else {
271
+ home.homeStorage = {
272
+ ...home.homeStorage,
273
+ ownerMachineId: home.machineId,
274
+ guestHome: m0Config.guestHome,
275
+ mountPath: m0Config.guestHome,
276
+ };
277
+ }
278
+ if ((typeof home.nodeId !== 'string' || home.nodeId.trim() === '') && config.seedHome?.nodeId) {
279
+ home.nodeId = config.seedHome.nodeId;
280
+ }
281
+ if ((typeof home.relayToken !== 'string' || home.relayToken.trim() === '') && config.seedHome?.relayToken) {
282
+ home.relayToken = config.seedHome.relayToken;
283
+ }
284
+ if (home.state === undefined || home.state === null || home.state === '') {
285
+ home.state = config.seedHome?.state ?? 'running';
286
+ }
287
+ if ((home.webRoute === undefined || home.webRoute === null) && config.seedHome?.webRouteUrl) {
288
+ home.webRoute = {
289
+ routeId: config.seedHome.webRouteUrl,
290
+ machineId: home.machineId,
291
+ targetPort: m0Config.webPort,
292
+ url: config.seedHome.webRouteUrl,
293
+ concreteUrl: config.seedHome.webRouteUrl,
294
+ concreteUrlSource: 'config',
295
+ createdAt: nowIso(),
296
+ raw: null,
297
+ };
298
+ }
299
+ home.updatedAt = nowIso();
300
+ });
301
+ return updated;
302
+ }
303
+ if (config.seedHome === null) {
304
+ throw general('hearth m0 registry is empty and no HEARTH_SEED_* values were provided — run the existing M0 provision/bootstrap flow before starting the wake proxy', {
305
+ registryPath: config.m0RegistryPath,
306
+ tenantId: config.defaultTenantId,
307
+ });
308
+ }
309
+ const now = nowIso();
310
+ const home = {
311
+ tenantId: config.seedHome.tenantId,
312
+ providerName: m0Config.providerName,
313
+ machineId: config.seedHome.machineId,
314
+ homeStorage: {
315
+ kind: 'volume',
316
+ durability: 'durable-volume',
317
+ longTermContract: true,
318
+ ownerMachineId: config.seedHome.machineId,
319
+ guestHome: m0Config.guestHome,
320
+ volumeId: config.seedHome.volumeId,
321
+ mountPath: m0Config.guestHome,
322
+ },
323
+ state: config.seedHome.state ?? 'running',
324
+ nodeId: config.seedHome.nodeId,
325
+ relayToken: config.seedHome.relayToken,
326
+ webRoute: config.seedHome.webRouteUrl
327
+ ? {
328
+ routeId: config.seedHome.webRouteUrl,
329
+ machineId: config.seedHome.machineId,
330
+ targetPort: m0Config.webPort,
331
+ url: config.seedHome.webRouteUrl,
332
+ concreteUrl: config.seedHome.webRouteUrl,
333
+ concreteUrlSource: 'config',
334
+ createdAt: now,
335
+ raw: null,
336
+ }
337
+ : null,
338
+ createdAt: now,
339
+ updatedAt: now,
340
+ };
341
+ return putHome(config.m0RegistryPath, home);
342
+ }
@@ -0,0 +1,76 @@
1
+ import type { GuestNodeId, MachineId, MachineState, M0Config, RelayToken, TenantId } from '../../core/hearth/types.js';
2
+ export interface HearthProxyOwnerState {
3
+ ownerUserId: string;
4
+ defaultTenantId: TenantId;
5
+ tokenHash: string;
6
+ createdAt: string;
7
+ }
8
+ export interface HearthProxyTenantState {
9
+ tenantId: TenantId;
10
+ ownerUserId: string;
11
+ m0RegistryPath: string;
12
+ idleAfterMs: number;
13
+ lastActivityAt: string | null;
14
+ lastWakeAt: string | null;
15
+ lastPauseAt: string | null;
16
+ updatedAt: string;
17
+ }
18
+ export interface HearthProxyState {
19
+ version: 1;
20
+ owner: HearthProxyOwnerState;
21
+ tenants: Record<TenantId, HearthProxyTenantState>;
22
+ }
23
+ export interface HearthProxySeedHome {
24
+ tenantId: TenantId;
25
+ machineId: MachineId;
26
+ nodeId: GuestNodeId;
27
+ relayToken: RelayToken;
28
+ volumeId: string;
29
+ state?: MachineState | null;
30
+ webRouteUrl?: string | null;
31
+ }
32
+ export interface HearthProxyConfig {
33
+ host: string;
34
+ port: number;
35
+ publicOrigin: string;
36
+ statePath: string;
37
+ m0RegistryPath: string;
38
+ ownerUserId: string;
39
+ defaultTenantId: TenantId;
40
+ ownerTokenHash: string;
41
+ idlePauseMs: number;
42
+ wakeTimeoutMs: number;
43
+ readyTimeoutMs: number;
44
+ cookieSecure: boolean;
45
+ seedHome: HearthProxySeedHome | null;
46
+ }
47
+ export interface HearthWakeProxyRuntime {
48
+ proxy: HearthProxyConfig;
49
+ m0: M0Config;
50
+ }
51
+ export type ActivityKind = 'http' | 'ws' | 'wake';
52
+ export interface TenantActivitySnapshot {
53
+ tenantId: TenantId;
54
+ counts: Record<ActivityKind, number>;
55
+ total: number;
56
+ idleDeadlineAt: string | null;
57
+ }
58
+ export interface ActivityHandle {
59
+ tenantId: TenantId;
60
+ kind: ActivityKind;
61
+ acquiredAt: string;
62
+ closed: boolean;
63
+ }
64
+ export interface AwakenedHome {
65
+ tenantId: TenantId;
66
+ nodeId: GuestNodeId;
67
+ routeUrl: string;
68
+ relayToken: RelayToken;
69
+ machineId: MachineId;
70
+ webPort: number;
71
+ }
72
+ export interface WakeProxyLogger {
73
+ info(message: string, details?: Record<string, unknown>): void;
74
+ warn(message: string, details?: Record<string, unknown>): void;
75
+ error(message: string, details?: Record<string, unknown>): void;
76
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // @crouton-kit/crouter — the sanctioned library surface (design D1).
2
2
  //
3
3
  // This barrel is the ONLY supported way to import crouter as a library; the
4
- // `exports` map gates off deep subpath imports, so consumers (notably
5
- // @crouton-kit/crouter-web) depend on exactly the symbols re-exported here.
4
+ // `exports` map gates off deep subpath imports, so consumers depend on exactly
5
+ // the symbols re-exported here notably the in-tree web client, which reaches
6
+ // the runtime through the `@crouton-kit/crouter/web` seam.
6
7
  // Everything below is a stable, server-facing surface: runtime control that
7
8
  // keeps the canvas-row ⇄ pi-session lockstep guarantees, read-only canvas/
8
9
  // telemetry queries, and the broker socket client + wire protocol. Nothing
@@ -85,7 +85,7 @@ after(() => {
85
85
  test('boot intro asserts the node\'s OWN identity up front (regression: forked node impersonated source)', () => {
86
86
  createNode(node('alpha', { name: 'fix-auth', kind: 'developer' }));
87
87
  const intro = buildContextIntro('alpha');
88
- assert.match(intro, /<crtr-identity>/, 'opens with an explicit identity block');
88
+ assert.match(intro, /<crtr-bearings>/, 'opens with the bearings section');
89
89
  assert.match(intro, /You are node alpha/, 'names the node by its own id');
90
90
  assert.match(intro, /kind developer/, 'states the node kind');
91
91
  // Gated (Option A): a fresh (non-fork) node's bearings are its FIRST entry, so
@@ -93,9 +93,10 @@ test('boot intro asserts the node\'s OWN identity up front (regression: forked n
93
93
  // naming the copied history "inherited reference material") is fork-only and must
94
94
  // NOT appear here.
95
95
  assert.ok(!/inherited reference material/.test(intro), 'a non-fork node carries no disown-the-earlier-narrative line');
96
- // The identity block must come BEFORE the <crtr-context> bearings, so it is the
97
- // first thing the model reads — the orienting frame, not a trailing note.
98
- assert.ok(intro.indexOf('<crtr-identity>') < intro.indexOf('<crtr-context'), 'identity assertion precedes the context bearings');
96
+ // Identity LEADS the bearings block (no wrapper of its own), so it is the first
97
+ // prose the model reads — the orienting frame, not a trailing note.
98
+ assert.match(intro, /<crtr-bearings>\nYou are node alpha/, 'identity leads the bearings block');
99
+ assert.ok(intro.indexOf('<crtr-bearings>') < intro.indexOf('<project_context>'), 'bearings precede project context');
99
100
  });
100
101
  test('a FORK\'s intro names the source and disowns it (regression: fork acted AS the source)', () => {
101
102
  // The source node whose conversation pi copied into the fork.
@@ -124,7 +125,7 @@ test('session_start INJECTS the fork\'s own bearings despite the inherited sourc
124
125
  createNode(node('srcA'));
125
126
  createNode(node('forkB', { fork_from: 'srcA' }));
126
127
  // A fork boots with the SOURCE's whole conversation copied in — including the
127
- // source's <crtr-context> intro entry (which names srcA, not forkB).
128
+ // source's bearings intro entry (which names srcA, not forkB).
128
129
  const inheritedSourceBlock = introEntry(buildContextIntro('srcA'));
129
130
  process.env['CRTR_NODE_ID'] = 'forkB';
130
131
  const pi = makeFakePi();
@@ -15,11 +15,11 @@
15
15
  //
16
16
  // The block carries: the path to the node's own context dir and the framing for
17
17
  // what belongs there (a shared document store for the other nodes). EVERY node
18
- // also gets a `<knowledge>` block rendered from the document substrate —
19
- // eligible `knowledge` docs at their system-prompt visibility rung, plus the
20
- // node's own node-local substrate docs — so the bearings name what to read on
21
- // demand. (Preferences surface as their own `<preferences>` block of the
22
- // system prompt, not in this block.) An
18
+ // also gets a `<memory kind="knowledge">` block rendered from the document
19
+ // substrate — eligible `knowledge` docs at their system-prompt visibility rung,
20
+ // plus the node's own node-local substrate docs — so the bearings name what to
21
+ // read on demand. (Preferences surface as their own `<memory kind="preference">`
22
+ // block of the system prompt, not in this block.) An
23
23
  // orchestrator additionally gets the across-refresh-cycles framing (the one
24
24
  // thing a terminal worker's bearings drop). The prose lives in
25
25
  // core/runtime/bearings.ts (shared with the promotion guidance dump).
@@ -31,8 +31,8 @@
31
31
  // (whose bearings name the SOURCE's node id), so the handler must NOT treat that
32
32
  // inherited block as ours; it only skips when a bearings block belonging to OUR
33
33
  // node is already present (exact `details.nodeId` stamp, content-match
34
- // fallback), otherwise it injects ours — whose <crtr-identity> block reasserts
35
- // the fork's identity over the inherited persona. This is ONE of two reinforcing
34
+ // fallback), otherwise it injects ours — whose identity assertion (leading the
35
+ // <crtr-bearings> block) reasserts the fork's identity over the inherited persona. This is ONE of two reinforcing
36
36
  // channels: spawn.ts ALSO prepends the same identity assertion to a fork's
37
37
  // kickoff prompt (the turn-triggering message), so the override does not rest on
38
38
  // a single trailing custom_message.
@@ -9,13 +9,13 @@
9
9
  // It owns the substrate's two new pi hooks:
10
10
  //
11
11
  // 1. before_agent_start — the BOOT system-prompt half. Splices the rendered
12
- // `<preferences>` + `<memory-guidance>` blocks into `event.systemPrompt`,
13
- // right after pi's native "Available tools" list (before the
14
- // `\n\nGuidelines:` anchor), so the substrate's standing directives sit in
15
- // the tool-selection frame the agent reads while choosing a capability —
16
- // mirroring the personal crouter-help.ts anchor logic. Falls back to
17
- // appending when the anchor is absent. (Knowledge rides the `<crtr-context>`
18
- // bearings message instead — see core/substrate/render.ts.)
12
+ // `<memory kind="preference">` block (memory-usage guidance + preferences)
13
+ // into `event.systemPrompt`, right after pi's native "Available tools" list
14
+ // (before the `\n\nGuidelines:` anchor), so the substrate's standing
15
+ // directives sit in the tool-selection frame the agent reads while choosing
16
+ // a capability — mirroring the personal crouter-help.ts anchor logic. Falls
17
+ // back to appending when the anchor is absent. (The `<memory kind="knowledge">`
18
+ // catalog rides the bearings message instead — see core/substrate/render.ts.)
19
19
  //
20
20
  // 2. tool_result (gated on `read`) — the ON-READ half. For each non-error
21
21
  // `read`, surfaces the substrate docs that should appear alongside the file
@@ -34,7 +34,7 @@
34
34
  // with no dep on the pi packages. Mirrors canvas-context-intro.ts.
35
35
  import { homedir } from 'node:os';
36
36
  import { join, resolve } from 'node:path';
37
- import { renderMemoryGuidance, renderOnReadDocs, renderPreferencesSection, } from '../core/substrate/index.js';
37
+ import { renderOnReadDocs, renderPreferencesSection, } from '../core/substrate/index.js';
38
38
  import { clearSessionCache } from '../core/substrate/session-cache.js';
39
39
  import { loadInjectedDocs, saveInjectedDocs } from '../core/substrate/injected-store.js';
40
40
  // ---------------------------------------------------------------------------
@@ -42,8 +42,8 @@ import { loadInjectedDocs, saveInjectedDocs } from '../core/substrate/injected-s
42
42
  // ---------------------------------------------------------------------------
43
43
  /** The stable seam that closes pi's native "Available tools" list. We splice the
44
44
  * substrate's boot sections right before it — the agent decides which capability
45
- * to reach for while reading the tools, so skills/preferences must sit there,
46
- * not far below. Mirrors crouter-help.ts. Falls back to appending if absent. */
45
+ * to reach for while reading the tools, so memory docs/preferences must sit
46
+ * there, not far below. Mirrors crouter-help.ts. Falls back to appending if absent. */
47
47
  const TOOLS_ANCHOR = '\n\nGuidelines:';
48
48
  /**
49
49
  * Register the document substrate's two render hooks on `pi`.
@@ -67,24 +67,21 @@ export function registerCanvasDocSubstrate(pi) {
67
67
  const injectedDocs = loadInjectedDocs(nodeId);
68
68
  pi.on('session_start', () => {
69
69
  // Only the per-session substrate PARSE cache resets each session (so the
70
- // corpus is re-scanned, picking up skill/memory writes). injectedDocs is
70
+ // corpus is re-scanned, picking up memory writes). injectedDocs is
71
71
  // transcript-scoped, not session-scoped — deliberately NOT cleared here.
72
72
  clearSessionCache();
73
73
  });
74
- // 1. BOOT system-prompt half — splice `<preferences>` + `<memory-guidance>`.
75
- // The guidance block is always present for a canvas node (the memory system
76
- // always exists), so the splice is never empty even when the preferences
77
- // tree is. (Knowledge no longer enters the system prompt it rides the
78
- // `<crtr-context>` bearings message via renderKnowledgeBlock.)
74
+ // 1. BOOT system-prompt half — splice the `<memory kind="preference">` block
75
+ // (memory-usage guidance + preferences). The guidance frame is always
76
+ // present for a canvas node (the memory system always exists), so the block
77
+ // is never empty even when no preference is eligible. (The knowledge catalog
78
+ // no longer enters the system prompt — it rides the bearings message via
79
+ // renderKnowledgeBlock.)
79
80
  pi.on('before_agent_start', (event) => {
80
81
  try {
81
- const sections = [
82
- renderPreferencesSection(nodeId),
83
- renderMemoryGuidance(),
84
- ].filter((s) => s !== '');
85
- if (sections.length === 0)
82
+ const block = renderPreferencesSection(nodeId);
83
+ if (block === '')
86
84
  return; // nothing eligible — leave the prompt untouched
87
- const block = sections.join('\n\n');
88
85
  const idx = event.systemPrompt.indexOf(TOOLS_ANCHOR);
89
86
  if (idx === -1) {
90
87
  return { systemPrompt: `${event.systemPrompt}\n\n${block}` };
@@ -25,9 +25,9 @@
25
25
  // viewing the node: a `focuses` viewport points at it
26
26
  // (tmux host) or ≥1 helloed viewer is connected to its
27
27
  // broker (job/attach.json). Running is a separate axis,
28
- // signaled by the dot glyph alone ( = engine active on
29
- // its host — which may be an unwatched backstage pane
30
- // or a paneless broker).
28
+ // signaled by the overlay-aware glyph (●/○/⟳/⚠) alone on
29
+ // its host — which may be an unwatched backstage pane or
30
+ // a paneless broker).
31
31
  // SELF = bold name — a quiet "you are here" marker.
32
32
  //
33
33
  // Folding is auto by default: a branch stays COLLAPSED unless its subtree holds
@@ -45,7 +45,7 @@
45
45
  // inside crouter's own tsc build without a dep on the pi packages.
46
46
  import { execFile } from 'node:child_process';
47
47
  import { fullName } from '../core/canvas/index.js';
48
- import { beginFrame, cNode, managerOf, liveReports, sortedChildIds, subtreeIds, climbRoot, computeSubtreeActivity, buildGraphModel, renderGraphRow, navLabel, coloredGlyph, truncate, tokensCell, cycleBadge, childBadge, liveBelowBadge, askBadge, activityCell, focusedNodeIds, graphWidgetBudget, fetchAsksMap, shortId, DIM, RESET, BOLD, YELLOW, GRAPH_HINT, } from '../core/canvas/nav-model.js';
48
+ import { beginFrame, cNode, managerOf, liveReports, sortedChildIds, subtreeIds, climbRoot, computeSubtreeActivity, buildGraphModel, renderGraphRow, navLabel, nodeGlyph, truncate, tokensCell, cycleBadge, childBadge, liveBelowBadge, askBadge, activityCell, focusedNodeIds, graphWidgetBudget, fetchAsksMap, shortId, DIM, RESET, BOLD, YELLOW, GRAPH_HINT, } from '../core/canvas/nav-model.js';
49
49
  import { readConfig } from '../core/config.js';
50
50
  import { onNavRerender } from './widget-order-bus.js';
51
51
  // ---------------------------------------------------------------------------
@@ -207,7 +207,7 @@ export function registerCanvasNav(pi) {
207
207
  else {
208
208
  const mn = cNode(mgr);
209
209
  const name = navLabel(mn, mgr);
210
- const mgrLine = truncate(`↑ ${name} ${coloredGlyph(mn)} ${DIM}${mn?.kind ?? ''}${RESET} ${DIM}${tokensCell(mgr)}${RESET}${cycleBadge(mn)}${childBadge(mn)}${liveBelowBadge(mn, activity.activeBelow)}${askBadge(mgr, asksMap)}${activityCell(mgr, mn)}`);
210
+ const mgrLine = truncate(`↑ ${name} ${nodeGlyph(mn)} ${DIM}${mn?.kind ?? ''}${RESET} ${DIM}${tokensCell(mgr)}${RESET}${cycleBadge(mn)}${childBadge(mn)}${liveBelowBadge(mn, activity.activeBelow)}${askBadge(mgr, asksMap)}${activityCell(mgr, mn)}`);
211
211
  ui.setWidget('crtr-managers', [mgrLine], { placement: 'aboveEditor' });
212
212
  }
213
213
  const reports = liveReports(nodeId);
@@ -220,7 +220,7 @@ export function registerCanvasNav(pi) {
220
220
  const name = navLabel(n, id).padEnd(nameW);
221
221
  const kind = `${DIM}${(n?.kind ?? '').padEnd(6)}${RESET}`;
222
222
  const tokens = `${DIM}${tokensCell(id).padStart(5)}${RESET}`;
223
- lines.push(truncate(` ${coloredGlyph(n)} ${name} ${kind} ${tokens}${cycleBadge(n)}${childBadge(n)}${liveBelowBadge(n, activity.activeBelow)}${askBadge(id, asksMap)}${activityCell(id, n)}`));
223
+ lines.push(truncate(` ${nodeGlyph(n)} ${name} ${kind} ${tokens}${cycleBadge(n)}${childBadge(n)}${liveBelowBadge(n, activity.activeBelow)}${askBadge(id, asksMap)}${activityCell(id, n)}`));
224
224
  }
225
225
  }
226
226
  // Self's own pending asks (no self row in BASE) → a trailing inline line.
@@ -477,6 +477,13 @@ export function registerCanvasNav(pi) {
477
477
  render();
478
478
  return { consume: true };
479
479
  }
480
+ if (isPlain(data, 'e')) {
481
+ // Expand → tmux: spread the cursor node's local subtree into a tiled tmux
482
+ // window (same action as the alt+c → e menu chord), for parity.
483
+ shellCrtr(['canvas', 'tmux-spread', cursorId ?? nodeId], render);
484
+ render();
485
+ return { consume: true };
486
+ }
480
487
  // Custom graphBinds — additive only (built-in keys reserved).
481
488
  for (const [key, bind] of Object.entries(navConfig.graphBinds)) {
482
489
  if (key.length !== 1 || RESERVED_GRAPH_KEYS.has(key))
@@ -517,8 +524,8 @@ export function registerCanvasNav(pi) {
517
524
  }
518
525
  };
519
526
  // -------------------------------------------------------------------------
520
- // Slash command + shortcut to toggle GRAPH (registered once per load, like
521
- // canvas-commands.ts; pi dedupes duplicate names on /reload).
527
+ // Slash command + shortcut to toggle GRAPH (registered once per load;
528
+ // pi dedupes duplicate names on /reload).
522
529
  // -------------------------------------------------------------------------
523
530
  if (typeof pi.registerCommand === 'function') {
524
531
  pi.registerCommand('graph', {
@@ -1,4 +1,4 @@
1
- type PiEvents = 'agent_start' | 'turn_end' | 'agent_end' | 'session_shutdown' | 'session_start' | 'tool_execution_start';
1
+ type PiEvents = 'agent_start' | 'turn_end' | 'agent_end' | 'session_shutdown' | 'session_start' | 'tool_execution_start' | 'tool_execution_end';
2
2
  interface PiLike {
3
3
  on: (event: PiEvents, handler: (event: any, ctx: any) => void | Promise<void>) => void;
4
4
  sendUserMessage: (content: string, options?: {