@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,35 @@
1
+ import type { NodeStatus } from './types.js';
2
+ import { type Fault, type FaultKind } from '../runtime/fault.js';
3
+ export declare const STATUS_GLYPH: Record<NodeStatus, string>;
4
+ export declare const STATUS_COLOR: Record<NodeStatus, number>;
5
+ export declare const HANGING_GLYPH = "\u26A0";
6
+ export declare const HANGING_COLOR = 33;
7
+ /** Short label for the fault kind. The overlay keeps one glyph and lets the
8
+ * label carry the distinction. */
9
+ export declare function hangingLabel(kind: FaultKind): string;
10
+ export interface NodeVisual {
11
+ glyph: string;
12
+ color: number;
13
+ /** Overlay word (hanging kind label / 'live'); undefined for a plain status
14
+ * (the caller supplies its own status word). */
15
+ word?: string;
16
+ bold?: boolean;
17
+ }
18
+ /** Resolve a node's glyph + hue + overlay word, applying the precedence
19
+ * hanging > streaming > status. */
20
+ export declare function resolveNodeVisual(status: NodeStatus, opts: {
21
+ streaming?: boolean;
22
+ hanging?: Fault | {
23
+ kind: FaultKind;
24
+ } | null;
25
+ }): NodeVisual;
26
+ /** Human-friendly active-fault disposition text. `auto` faults show the current
27
+ * retry attempt plus the next scheduled retry; client-owned redials say
28
+ * `redialing`; everything else says `needs you`. */
29
+ export declare function faultDispositionText(fault: Fault, now?: number): string;
30
+ /** One-line active-fault summary used by the canvas surfaces: `link kind ·
31
+ * disposition`. */
32
+ export declare function faultSummary(fault: Fault, now?: number): string;
33
+ /** Elapsed counter used by the browse rail's countdown slot. `faultSummary`
34
+ * covers the presenter surfaces; this stays for the rail's existing time text. */
35
+ export declare function hangingCountdown(since: string, now?: number): string;
@@ -0,0 +1,104 @@
1
+ // status-glyph.ts — the canonical status→glyph/color map + overlay resolution
2
+ // for the TS canvas-GRAPH surfaces (the ASCII forest `render.ts` and the
3
+ // interactive `browse/render.ts`). It replaces the copy-pasted STATUS_GLYPH /
4
+ // STATUS_COLOR literals those two files used to carry.
5
+ //
6
+ // SCOPE: only the surfaces the hanging-node feature touches. The workspace rail,
7
+ // feed/push roster, and attach chat-view keep their own glyph copies (out of
8
+ // scope). The portable `.mjs` canvas monitor view CANNOT import this (TS dist) —
9
+ // it carries its own mirrored map with a pointer back to fault.ts.
10
+ //
11
+ // OVERLAY PRECEDENCE: hanging > streaming > status. `hanging` and `streaming` are
12
+ // mutually exclusive in practice (hanging means the turn ended, so `busy` is
13
+ // gone) but the precedence is defined regardless.
14
+ import { FAULT_QUIET_MS } from '../runtime/fault.js';
15
+ // ── Status glyphs (the mono, color-free primary encoding) ─────────────────────
16
+ export const STATUS_GLYPH = {
17
+ active: '●',
18
+ idle: '○',
19
+ done: '✓',
20
+ dead: '✗',
21
+ canceled: '⊘',
22
+ };
23
+ // ── Status hue: numeric SGR codes per status (lifted from browse/render.ts). ───
24
+ // Reinforces the glyph; the glyph SHAPE stays the NO_COLOR carrier.
25
+ export const STATUS_COLOR = {
26
+ active: 32, // green
27
+ idle: 33, // yellow
28
+ done: 36, // cyan
29
+ dead: 31, // red
30
+ canceled: 90, // grey (bright-black)
31
+ };
32
+ // ── Streaming overlay (genuinely mid-turn) — browse's existing statusRail visual.
33
+ const STREAMING_GLYPH = '⟳';
34
+ const STREAMING_COLOR = 92; // bright green (brighter than active-status green)
35
+ // ── Active-fault overlay (one glyph, kind label carries the detail). ─────────
36
+ export const HANGING_GLYPH = '⚠';
37
+ export const HANGING_COLOR = 33; // yellow
38
+ /** Short label for the fault kind. The overlay keeps one glyph and lets the
39
+ * label carry the distinction. */
40
+ export function hangingLabel(kind) {
41
+ switch (kind) {
42
+ case 'rate-limit': return 'rate-limited';
43
+ case 'overloaded': return 'overloaded';
44
+ case 'connection': return 'down';
45
+ case 'auth': return 'auth';
46
+ case 'protocol': return 'protocol';
47
+ default: return 'other';
48
+ }
49
+ }
50
+ /** Resolve a node's glyph + hue + overlay word, applying the precedence
51
+ * hanging > streaming > status. */
52
+ export function resolveNodeVisual(status, opts) {
53
+ if (opts.hanging != null) {
54
+ return { glyph: HANGING_GLYPH, color: HANGING_COLOR, word: hangingLabel(opts.hanging.kind), bold: true };
55
+ }
56
+ if (opts.streaming === true) {
57
+ return { glyph: STREAMING_GLYPH, color: STREAMING_COLOR, word: 'live', bold: true };
58
+ }
59
+ return { glyph: STATUS_GLYPH[status] ?? '?', color: STATUS_COLOR[status] };
60
+ }
61
+ function retryCountdown(iso, now) {
62
+ const at = Date.parse(iso);
63
+ if (Number.isNaN(at))
64
+ return 'now';
65
+ const remaining = at - now;
66
+ if (remaining <= 0)
67
+ return 'now';
68
+ if (remaining >= 60_000)
69
+ return `${Math.max(1, Math.round(remaining / 60_000))}m`;
70
+ return `${Math.max(1, Math.ceil(remaining / 1000))}s`;
71
+ }
72
+ /** Human-friendly active-fault disposition text. `auto` faults show the current
73
+ * retry attempt plus the next scheduled retry; client-owned redials say
74
+ * `redialing`; everything else says `needs you`. */
75
+ export function faultDispositionText(fault, now = Date.now()) {
76
+ const retry = fault.retry;
77
+ if (retry.disposition === 'auto') {
78
+ if (retry.by === 'client')
79
+ return 'redialing';
80
+ const progress = typeof retry.attempt === 'number' && typeof retry.max === 'number'
81
+ ? `auto-retry ${retry.attempt}/${retry.max}`
82
+ : 'auto-retrying';
83
+ return retry.nextAt ? `${progress}, next ${retryCountdown(retry.nextAt, now)}` : progress;
84
+ }
85
+ return 'needs you';
86
+ }
87
+ /** One-line active-fault summary used by the canvas surfaces: `link kind ·
88
+ * disposition`. */
89
+ export function faultSummary(fault, now = Date.now()) {
90
+ return `${fault.link} ${hangingLabel(fault.kind)} · ${faultDispositionText(fault, now)}`;
91
+ }
92
+ /** Elapsed counter used by the browse rail's countdown slot. `faultSummary`
93
+ * covers the presenter surfaces; this stays for the rail's existing time text. */
94
+ export function hangingCountdown(since, now = Date.now()) {
95
+ const start = Date.parse(since);
96
+ if (Number.isNaN(start))
97
+ return 'retrying…';
98
+ const remaining = FAULT_QUIET_MS - (now - start);
99
+ if (remaining <= 0)
100
+ return 'retrying…';
101
+ if (remaining >= 60_000)
102
+ return `retry in ~${Math.max(1, Math.round(remaining / 60_000))}m`;
103
+ return `retry in ~${Math.ceil(remaining / 1000)}s`;
104
+ }
@@ -47,8 +47,8 @@ export interface NodeIdentity {
47
47
  * headlessly by pi; see runtime/naming.ts). Shown in the editor label. */
48
48
  description?: string;
49
49
  /** How many times this node has been (re)launched — born at 0, bumped on
50
- * every revive. The trailing N in the editor label, so a refresh/crash cycle
51
- * reads at a glance. */
50
+ * every revive. Exposed to the pi footer as CRTR_CYCLES so a refresh/crash
51
+ * cycle reads at a glance there. */
52
52
  cycles?: number;
53
53
  created: string;
54
54
  /** The dir this node is pinned to — its cwd (where pi runs, bash executes). */
@@ -1,5 +1,5 @@
1
1
  import { join } from 'node:path';
2
- import { CONFIG_FILE, STATE_FILE, defaultScopeConfig, defaultScopeState, defaultCanvasNavConfig } from '../types.js';
2
+ import { CONFIG_FILE, STATE_FILE, defaultScopeConfig, defaultScopeState, defaultCanvasNavConfig, defaultModelLaddersConfig } from '../types.js';
3
3
  import { readJsonIfExists, writeJson, ensureDir } from './fs-utils.js';
4
4
  import { scopeRoot, requireScopeRoot } from './scope.js';
5
5
  function configPathFor(root) {
@@ -56,21 +56,82 @@ export function ensureScopeInitialized(scope, root) {
56
56
  writeJson(cfgPath, defaultScopeConfig());
57
57
  }
58
58
  }
59
+ function prefixBindDesc(desc) {
60
+ return typeof desc === 'string' && desc !== '' ? { desc } : {};
61
+ }
62
+ function normalizePrefixMenuItem(raw) {
63
+ if (raw === null || typeof raw !== 'object')
64
+ return null;
65
+ const r = raw;
66
+ const key = typeof r.key === 'string' && r.key !== '' ? r.key : null;
67
+ const desc = typeof r.desc === 'string' && r.desc !== '' ? r.desc : null;
68
+ const action = normalizePrefixBind(r.action);
69
+ if (key === null || desc === null || action === null)
70
+ return null;
71
+ const out = { key, desc, action };
72
+ if (r.confirm === true)
73
+ out.confirm = true;
74
+ return out;
75
+ }
76
+ function normalizePrefixBind(raw) {
77
+ if (raw === null || typeof raw !== 'object')
78
+ return null;
79
+ const r = raw;
80
+ const desc = prefixBindDesc(r.desc);
81
+ const confirm = r.confirm === true ? { confirm: true } : {};
82
+ if (typeof r.run === 'string') {
83
+ if (r.run === '__graph__')
84
+ return { kind: 'keys', keys: '/graph', ...desc };
85
+ if (r.run === '__issue__') {
86
+ return {
87
+ kind: 'menu',
88
+ items: [
89
+ { key: 'i', desc: 'idea', action: { kind: 'popup', run: 'canvas issue new --type idea' } },
90
+ { key: 'b', desc: 'bug', action: { kind: 'popup', run: 'canvas issue new --type bug' } },
91
+ ],
92
+ ...desc,
93
+ };
94
+ }
95
+ }
96
+ if (r.kind === 'keys' && typeof r.keys === 'string')
97
+ return { kind: 'keys', keys: r.keys, ...desc };
98
+ if (r.kind === 'popup' && typeof r.run === 'string')
99
+ return { kind: 'popup', run: r.run, ...desc };
100
+ if (r.kind === 'menu' && Array.isArray(r.items)) {
101
+ const items = r.items.map(normalizePrefixMenuItem).filter((item) => item !== null);
102
+ if (items.length !== r.items.length)
103
+ return null;
104
+ return { kind: 'menu', items, ...desc };
105
+ }
106
+ if ((r.kind === undefined || r.kind === 'crtr') && typeof r.run === 'string') {
107
+ return { kind: 'crtr', run: r.run, ...confirm, ...desc };
108
+ }
109
+ if (r.kind === undefined && typeof r.keys === 'string')
110
+ return { kind: 'keys', keys: r.keys, ...desc };
111
+ return null;
112
+ }
113
+ function normalizeGraphBind(raw) {
114
+ if (raw === null || typeof raw !== 'object')
115
+ return null;
116
+ const r = raw;
117
+ if (typeof r.run !== 'string')
118
+ return null;
119
+ return {
120
+ run: r.run,
121
+ ...(r.confirm === true ? { confirm: true } : {}),
122
+ ...(typeof r.desc === 'string' && r.desc !== '' ? { desc: r.desc } : {}),
123
+ };
124
+ }
59
125
  /** Deep-merge one bind table over its built-in defaults: a user adding a single
60
- * bind must not wipe the rest. Each user entry is validated (a `run` string is
61
- * required) before it replaces/extends a key. */
62
- function mergeBinds(base, over) {
126
+ * bind must not wipe the rest. Each user entry is normalized before it
127
+ * replaces/extends a key. */
128
+ function mergeBinds(base, over, normalize) {
63
129
  const out = { ...base };
64
130
  if (over !== null && typeof over === 'object') {
65
131
  for (const [k, v] of Object.entries(over)) {
66
- if (v !== null && typeof v === 'object' && typeof v.run === 'string') {
67
- const b = v;
68
- out[k] = {
69
- run: b.run,
70
- ...(b.confirm === true ? { confirm: true } : {}),
71
- ...(typeof b.desc === 'string' ? { desc: b.desc } : {}),
72
- };
73
- }
132
+ const normalized = normalize(v);
133
+ if (normalized !== null)
134
+ out[k] = normalized;
74
135
  }
75
136
  }
76
137
  return out;
@@ -85,9 +146,44 @@ function mergeCanvasNav(raw) {
85
146
  const prefixKey = typeof r.prefixKey === 'string' && r.prefixKey.trim() !== '' ? r.prefixKey : defaults.prefixKey;
86
147
  return {
87
148
  prefixKey,
88
- prefixBinds: mergeBinds(defaults.prefixBinds, r.prefixBinds),
89
- graphBinds: mergeBinds(defaults.graphBinds, r.graphBinds),
149
+ prefixBinds: mergeBinds(defaults.prefixBinds, r.prefixBinds, normalizePrefixBind),
150
+ graphBinds: mergeBinds(defaults.graphBinds, r.graphBinds, normalizeGraphBind),
151
+ };
152
+ }
153
+ function mergeModelLadders(raw) {
154
+ const defaults = defaultModelLaddersConfig();
155
+ if (raw === null || typeof raw !== 'object')
156
+ return defaults;
157
+ const r = raw;
158
+ const out = {
159
+ anthropic: { ...defaults.anthropic },
160
+ openai: { ...defaults.openai },
90
161
  };
162
+ if (r.defaultProvider === 'anthropic' || r.defaultProvider === 'openai') {
163
+ out.defaultProvider = r.defaultProvider;
164
+ }
165
+ for (const provider of ['anthropic', 'openai']) {
166
+ const over = r[provider];
167
+ if (over === null || typeof over !== 'object')
168
+ continue;
169
+ for (const [strength, value] of Object.entries(over)) {
170
+ if ((strength === 'ultra' || strength === 'strong' || strength === 'medium' || strength === 'light') && typeof value === 'string') {
171
+ out[provider][strength] = value;
172
+ }
173
+ }
174
+ }
175
+ return out;
176
+ }
177
+ function mergePersonaStrengths(raw) {
178
+ const out = {};
179
+ if (raw === null || typeof raw !== 'object')
180
+ return out;
181
+ for (const [persona, value] of Object.entries(raw)) {
182
+ if (value === 'ultra' || value === 'strong' || value === 'medium' || value === 'light') {
183
+ out[persona] = value;
184
+ }
185
+ }
186
+ return out;
91
187
  }
92
188
  function normalizeMode(value, fallback) {
93
189
  if (value === true)
@@ -100,7 +196,7 @@ function normalizeMode(value, fallback) {
100
196
  }
101
197
  function mergeConfig(partial) {
102
198
  const defaults = defaultScopeConfig();
103
- const schema_version = partial.schema_version === undefined ? defaults.schema_version : partial.schema_version;
199
+ const schema_version = defaults.schema_version;
104
200
  const marketplaces = partial.marketplaces === undefined ? {} : partial.marketplaces;
105
201
  const plugins = partial.plugins === undefined ? {} : partial.plugins;
106
202
  const au = partial.auto_update;
@@ -118,7 +214,9 @@ function mergeConfig(partial) {
118
214
  ? Math.floor(rawMaxPanes)
119
215
  : defaults.max_panes_per_window;
120
216
  const canvasNav = mergeCanvasNav(partial.canvasNav);
121
- return { schema_version, marketplaces, plugins, auto_update, max_panes_per_window, canvasNav };
217
+ const modelLadders = mergeModelLadders(partial.modelLadders);
218
+ const personaStrengths = mergePersonaStrengths(partial.personaStrengths);
219
+ return { schema_version, marketplaces, plugins, auto_update, max_panes_per_window, canvasNav, modelLadders, personaStrengths };
122
220
  }
123
221
  export function updateConfig(scope, mutate) {
124
222
  const cfg = readConfig(scope);
@@ -0,0 +1,41 @@
1
+ export type FaultLink = 'pi→provider' | 'viewer↔broker' | 'relay↔broker' | 'browser↔relay' | 'cli→exa';
2
+ export type FaultKind = 'rate-limit' | 'overloaded' | 'connection' | 'auth' | 'protocol' | 'other';
3
+ export type FaultRetryDisposition = 'auto' | 'manual' | 'fatal';
4
+ export type FaultRetryOwner = 'sdk' | 'daemon' | 'client';
5
+ export interface FaultRetry {
6
+ disposition: FaultRetryDisposition;
7
+ by?: FaultRetryOwner;
8
+ attempt?: number;
9
+ max?: number;
10
+ nextAt?: string;
11
+ }
12
+ export interface Fault {
13
+ link: FaultLink;
14
+ op: string;
15
+ kind: FaultKind;
16
+ retry: FaultRetry;
17
+ message: string;
18
+ since: string;
19
+ logPath: string;
20
+ anchorEntryId?: string;
21
+ }
22
+ export interface FaultClassification {
23
+ kind: FaultKind;
24
+ disposition: FaultRetryDisposition;
25
+ }
26
+ export interface FaultErrnoLike {
27
+ code?: unknown;
28
+ errno?: unknown;
29
+ message?: unknown;
30
+ }
31
+ export interface FaultHttpLike {
32
+ status?: unknown;
33
+ statusText?: unknown;
34
+ ok?: unknown;
35
+ message?: unknown;
36
+ }
37
+ export interface FaultWsCloseLike {
38
+ code?: unknown;
39
+ reason?: unknown;
40
+ }
41
+ export declare function classify(link: FaultLink, raw: unknown): FaultClassification;
@@ -0,0 +1,110 @@
1
+ function isRecord(value) {
2
+ return typeof value === 'object' && value !== null;
3
+ }
4
+ function text(value) {
5
+ return typeof value === 'string' ? value : '';
6
+ }
7
+ function classifyProviderText(message) {
8
+ const m = message ?? '';
9
+ // ORDER MATTERS: rate-limit → overloaded → connection → other.
10
+ if (/rate.?limit|\b429\b|too many requests|quota/i.test(m))
11
+ return 'rate-limit';
12
+ if (/overloaded|\b529\b|\b503\b|capacity|server.{0,3}busy|temporarily unavailable/i.test(m))
13
+ return 'overloaded';
14
+ if (/connection|econnreset|etimedout|enotfound|econnrefused|network|fetch failed|socket hang|timed? out|timeout/i.test(m))
15
+ return 'connection';
16
+ return 'other';
17
+ }
18
+ function classifyErrno(raw) {
19
+ const code = text(raw.code) || text(raw.errno);
20
+ if (code === '')
21
+ return null;
22
+ if (/^(ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOENT|ENOTFOUND|EAI_AGAIN|EPIPE|EHOSTUNREACH|ENETUNREACH)$/i.test(code)) {
23
+ return 'connection';
24
+ }
25
+ return null;
26
+ }
27
+ function classifyHttp(raw) {
28
+ const status = typeof raw.status === 'number' ? raw.status : null;
29
+ if (status === null)
30
+ return null;
31
+ if (status === 401 || status === 403)
32
+ return 'auth';
33
+ if (status === 429)
34
+ return 'rate-limit';
35
+ if (status === 503 || status === 529)
36
+ return 'overloaded';
37
+ if (status >= 500 && status <= 599)
38
+ return 'overloaded';
39
+ if (status >= 400 && status <= 499)
40
+ return 'protocol';
41
+ return null;
42
+ }
43
+ function classifyWsClose(raw) {
44
+ const code = typeof raw.code === 'number' ? raw.code : null;
45
+ if (code === null)
46
+ return null;
47
+ if (code === 1008)
48
+ return 'protocol';
49
+ if (code === 1006)
50
+ return 'connection';
51
+ if (code === 1011) {
52
+ const reason = text(raw.reason);
53
+ if (/no running broker/i.test(reason))
54
+ return 'connection';
55
+ return classifyProviderText(reason) === 'connection' ? 'connection' : 'other';
56
+ }
57
+ return null;
58
+ }
59
+ function classifyDisposition(link, kind) {
60
+ if (kind === 'auth' || kind === 'protocol')
61
+ return 'fatal';
62
+ if (link === 'pi→provider') {
63
+ if (kind === 'connection' || kind === 'rate-limit' || kind === 'overloaded')
64
+ return 'auto';
65
+ return 'fatal';
66
+ }
67
+ return 'manual';
68
+ }
69
+ function rawText(raw) {
70
+ if (typeof raw === 'string')
71
+ return raw;
72
+ if (!isRecord(raw))
73
+ return '';
74
+ const candidates = [
75
+ raw['message'],
76
+ raw['errorMessage'],
77
+ raw['reason'],
78
+ raw['body'],
79
+ raw['statusText'],
80
+ ];
81
+ for (const candidate of candidates) {
82
+ if (typeof candidate === 'string' && candidate !== '')
83
+ return candidate;
84
+ }
85
+ const nested = raw['error'];
86
+ if (isRecord(nested)) {
87
+ const nestedMessage = nested['message'];
88
+ if (typeof nestedMessage === 'string' && nestedMessage !== '')
89
+ return nestedMessage;
90
+ const nestedReason = nested['reason'];
91
+ if (typeof nestedReason === 'string' && nestedReason !== '')
92
+ return nestedReason;
93
+ }
94
+ return '';
95
+ }
96
+ export function classify(link, raw) {
97
+ if (isRecord(raw)) {
98
+ const errno = classifyErrno(raw);
99
+ if (errno !== null)
100
+ return { kind: errno, disposition: classifyDisposition(link, errno) };
101
+ const http = classifyHttp(raw);
102
+ if (http !== null)
103
+ return { kind: http, disposition: classifyDisposition(link, http) };
104
+ const ws = classifyWsClose(raw);
105
+ if (ws !== null)
106
+ return { kind: ws, disposition: classifyDisposition(link, ws) };
107
+ }
108
+ const kind = classifyProviderText(rawText(raw));
109
+ return { kind, disposition: classifyDisposition(link, kind) };
110
+ }
@@ -2,6 +2,10 @@ export type InboxTier = 'critical' | 'urgent' | 'normal' | 'deferred';
2
2
  export type InboxKind = 'update' | 'urgent' | 'final' | 'message' | 'completed';
3
3
  /** A single inbox entry — a pointer, not a copy of the content. */
4
4
  export interface InboxEntry {
5
+ /** Short stable handle for addressing this entry from the CLI (`feed message
6
+ * <id>`). Set when the entry carries an inline body too long to fully inline
7
+ * in the digest, so the receiver can read the full text back by id. */
8
+ id?: string;
5
9
  /** ISO 8601 timestamp of delivery. */
6
10
  ts: string;
7
11
  /** Node id of the sender, or null for system-generated entries. */
@@ -22,6 +26,8 @@ export interface InboxEntry {
22
26
  * Fills `ts` (current ISO time). Returns the completed entry.
23
27
  */
24
28
  export declare function appendInbox(nodeId: string, entry: Omit<InboxEntry, 'ts'>): InboxEntry;
29
+ /** Find one inbox entry by its short `id` handle (see `feed message <id>`). */
30
+ export declare function readInboxEntryById(nodeId: string, id: string): InboxEntry | undefined;
25
31
  /**
26
32
  * Return all inbox entries strictly after `cursorIso`.
27
33
  * When `cursorIso` is undefined, returns every entry in the file.
@@ -36,6 +42,15 @@ export declare function readCursor(nodeId: string): string | undefined;
36
42
  * Persist a new cursor ISO for a node's inbox (atomic tmp+rename).
37
43
  */
38
44
  export declare function writeCursor(nodeId: string, iso: string): void;
45
+ /** True when an entry's inline body is long enough that the digest will clip it
46
+ * — the trigger for minting an addressable `id` so the full text stays
47
+ * recoverable via `feed message <id>`. */
48
+ export declare function bodyExceedsPreview(e: Pick<InboxEntry, 'data' | 'label'>): boolean;
49
+ /** Clip a body to a bounded preview, reporting whether anything was dropped. */
50
+ export declare function clipBody(body: string): {
51
+ text: string;
52
+ clipped: boolean;
53
+ };
39
54
  /**
40
55
  * Render many unread inbox pointers into one compact digest string.
41
56
  *
@@ -9,6 +9,7 @@
9
9
  // nodes/<id>/inbox.jsonl.cursor — ISO 8601 of last-read entry (sidecar)
10
10
  import { appendFileSync, existsSync, readFileSync, writeFileSync, renameSync, mkdirSync, } from 'node:fs';
11
11
  import { dirname } from 'node:path';
12
+ import { randomUUID } from 'node:crypto';
12
13
  import { inboxPath } from '../canvas/index.js';
13
14
  // ---------------------------------------------------------------------------
14
15
  // Cursor sidecar path
@@ -25,6 +26,10 @@ function cursorPath(nodeId) {
25
26
  */
26
27
  export function appendInbox(nodeId, entry) {
27
28
  const full = { ts: new Date().toISOString(), ...entry };
29
+ // A message that carries an inline body the digest will clip needs a stable
30
+ // handle so the receiver can read the full text back (`feed message <id>`).
31
+ if (full.id === undefined && bodyExceedsPreview(full))
32
+ full.id = randomUUID().slice(0, 8);
28
33
  const line = JSON.stringify(full) + '\n';
29
34
  // Ensure the parent directory exists (inbox.jsonl lives directly under the
30
35
  // node dir, which ensureNodeDirs creates — but guard anyway for callers that
@@ -41,6 +46,10 @@ export function appendInbox(nodeId, entry) {
41
46
  // ---------------------------------------------------------------------------
42
47
  // Read
43
48
  // ---------------------------------------------------------------------------
49
+ /** Find one inbox entry by its short `id` handle (see `feed message <id>`). */
50
+ export function readInboxEntryById(nodeId, id) {
51
+ return readInboxSince(nodeId, undefined).find((e) => e.id === id);
52
+ }
44
53
  /**
45
54
  * Return all inbox entries strictly after `cursorIso`.
46
55
  * When `cursorIso` is undefined, returns every entry in the file.
@@ -89,11 +98,25 @@ export function writeCursor(nodeId, iso) {
89
98
  // ---------------------------------------------------------------------------
90
99
  // Coalesce
91
100
  // ---------------------------------------------------------------------------
92
- /** Bounds for inlining a ref-less entry's body in the digest. */
101
+ /** Bounds for inlining a message body's preview in the digest. */
93
102
  const BODY_MAX_LINES = 12;
94
103
  const BODY_MAX_CHARS = 1000;
104
+ /** The inline body an entry carries (a direct msg / system alert), trimmed.
105
+ * Empty for a push pointer (whose body lives at `ref`) or a one-line entry
106
+ * whose `label` already IS the whole message. */
107
+ function inlineBody(e) {
108
+ const body = typeof e.data?.['body'] === 'string' ? e.data['body'].trim() : '';
109
+ return body === '' || body === e.label ? '' : body;
110
+ }
111
+ /** True when an entry's inline body is long enough that the digest will clip it
112
+ * — the trigger for minting an addressable `id` so the full text stays
113
+ * recoverable via `feed message <id>`. */
114
+ export function bodyExceedsPreview(e) {
115
+ const body = inlineBody(e);
116
+ return body !== '' && clipBody(body).clipped;
117
+ }
95
118
  /** Clip a body to a bounded preview, reporting whether anything was dropped. */
96
- function clipBody(body) {
119
+ export function clipBody(body) {
97
120
  let text = body;
98
121
  let clipped = false;
99
122
  const lines = text.split('\n');
@@ -111,23 +134,26 @@ function clipBody(body) {
111
134
  * Render one entry's digest line(s).
112
135
  *
113
136
  * A push pointer (has a `ref`) stays a pointer — the body lives in the report
114
- * file, dereferenced on demand by reading that path. A ref-less entry (a direct
115
- * `node msg` or a system alert) has NO report to dereference; its full body
116
- * lives only in `data.body`, and `label` is just the first line truncated. So
117
- * for those we inline the body (bounded) rendering only the truncated label
118
- * would strand the rest with nowhere to recover it.
137
+ * file, dereferenced on demand by reading that path. A direct `node msg` or
138
+ * system alert has NO report to dereference; its full body lives in the
139
+ * inbox.jsonl entry itself (`data.body`), so we inline a bounded preview. When
140
+ * that preview clips, the entry carries a short `id` and we point at the CLI
141
+ * command that reads the full body back from the jsonl (`feed message <id>`).
119
142
  */
120
143
  function renderEntry(e) {
121
- if (e.ref !== undefined) {
122
- return ` [${e.kind}] ${e.label} (ref: ${e.ref})`;
123
- }
124
- const body = typeof e.data?.['body'] === 'string' ? e.data['body'].trim() : '';
125
- if (body === '' || body === e.label) {
126
- return ` [${e.kind}] ${e.label}`;
144
+ const body = inlineBody(e);
145
+ if (body === '') {
146
+ return e.ref !== undefined
147
+ ? ` [${e.kind}] ${e.label} (ref: ${e.ref})`
148
+ : ` [${e.kind}] ${e.label}`;
127
149
  }
128
150
  const { text, clipped } = clipBody(body);
129
151
  const indented = text.split('\n').map((l) => ` ${l}`).join('\n');
130
- const more = clipped ? '\n … (body clipped)' : '';
152
+ const more = clipped
153
+ ? (e.id !== undefined
154
+ ? `\n … (clipped — full message: \`crtr feed message ${e.id}\`)`
155
+ : '\n … (body clipped)')
156
+ : '';
131
157
  return ` [${e.kind}]\n${indented}${more}`;
132
158
  }
133
159
  /**
@@ -1,18 +1,8 @@
1
- import { type SkillFrontmatter } from '../types.js';
2
- export interface ParsedFrontmatter {
3
- data: SkillFrontmatter | null;
4
- body: string;
5
- raw: string;
6
- }
7
- export declare function parseFrontmatter(source: string): ParsedFrontmatter;
8
1
  export interface ParsedFrontmatterGeneric {
9
2
  /** Raw, uncoerced key/value record from the YAML block (null when absent). */
10
3
  data: Record<string, unknown> | null;
11
4
  body: string;
12
5
  raw: string;
13
6
  }
14
- /** Like parseFrontmatter but returns the raw key/value record instead of
15
- * coercing to SkillFrontmatter. Used by consumers (e.g. subagents) that read
16
- * fields skills don't declare, such as `tools` and `model`. */
7
+ /** Parse a frontmatter block as a raw key/value record. */
17
8
  export declare function parseFrontmatterGeneric(source: string): ParsedFrontmatterGeneric;
18
- export declare function serializeFrontmatter(data: SkillFrontmatter): string;