@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,397 @@
1
+ // @ts-check
2
+ /**
3
+ * Model ladders settings — portable core for the `settings` view.
4
+ *
5
+ * Reads/writes go through crtr commands (`sys config get` / `sys config set`)
6
+ * so both targets use the existing /__crtr/source bridge.
7
+ *
8
+ * @module settings/core
9
+ */
10
+
11
+ /** @typedef {import('../../core/view/contract.js').SourceError} SourceError */
12
+ /** @typedef {import('../../core/view/contract.js').IntentCtx<SettingsState>} Ctx */
13
+ /** @typedef {import('../../types.js').ModelLaddersConfig} ModelLaddersConfig */
14
+ /** @typedef {import('../../types.js').ModelStrength} ModelStrength */
15
+ /** @typedef {import('../../types.js').ModelProvider} ModelProvider */
16
+
17
+ const USER_SCOPE = 'user';
18
+ const STRENGTHS = ['ultra', 'strong', 'medium', 'light'];
19
+ /** @type {Record<ModelStrength, ModelProvider>} */
20
+ const DEFAULT_MATRIX_SELECTION = { ultra: 'anthropic', strong: 'anthropic', medium: 'anthropic', light: 'anthropic' };
21
+
22
+ /** @template T @param {T} data @returns {{ok:true, data:T}} */
23
+ function ok(data) { return { ok: true, data }; }
24
+ /** @param {SourceError} error @returns {{ok:false, error:SourceError}} */
25
+ function fail(error) { return { ok: false, error }; }
26
+
27
+ /** @param {unknown} v @returns {string} */
28
+ function str(v) { return v == null ? '' : String(v); }
29
+
30
+ /** @param {string} msg @param {SourceError['display']['level']} [level='error'] @returns {SourceError} */
31
+ function settingsError(msg, level = 'error') {
32
+ return {
33
+ kind: 'settings-config',
34
+ display: {
35
+ headline: 'Settings unavailable',
36
+ explanation: msg,
37
+ nextStep: 'Press g to retry.',
38
+ level,
39
+ blocking: level === 'error',
40
+ },
41
+ };
42
+ }
43
+
44
+ /** @param {string} key @returns {import('../../core/view/contract.js').Source<unknown>} */
45
+ function makeConfigGetSource(key) {
46
+ return {
47
+ id: `config-get-${key}`,
48
+ request: () => ({ kind: 'exec', bin: 'crtr', args: ['sys', 'config', 'get', key, '--scope', USER_SCOPE, '--json'] }),
49
+ parse: (raw) => {
50
+ if (!raw.ok || raw.exitCode !== 0) return fail(settingsError(str(raw.stderr || raw.stdout || `crtr sys config get ${key} failed`)));
51
+ let data;
52
+ try {
53
+ data = JSON.parse(String(raw.stdout || '').trim() || '{}');
54
+ } catch {
55
+ return fail(settingsError(`could not parse crtr sys config get ${key} output as JSON`));
56
+ }
57
+ if (!data || typeof data !== 'object' || !('value' in data)) {
58
+ return fail(settingsError(`unexpected response from crtr sys config get ${key}`));
59
+ }
60
+ return ok(/** @type {unknown} */ (data).value);
61
+ },
62
+ };
63
+ }
64
+
65
+ /** @param {string} key @param {string} value @returns {import('../../core/view/contract.js').Command<unknown>} */
66
+ function makeConfigSetCommand(key, value) {
67
+ return {
68
+ id: `config-set-${key}`,
69
+ request: () => ({ kind: 'exec', bin: 'crtr', args: ['sys', 'config', 'set', key, '--value', value, '--scope', USER_SCOPE, '--json'] }),
70
+ parse: (raw) => {
71
+ if (!raw.ok || raw.exitCode !== 0) return fail(settingsError(str(raw.stderr || raw.stdout || `crtr sys config set ${key} failed`), 'error'));
72
+ let data;
73
+ try {
74
+ data = JSON.parse(String(raw.stdout || '').trim() || '{}');
75
+ } catch {
76
+ return fail(settingsError(`could not parse crtr sys config set ${key} output as JSON`));
77
+ }
78
+ if (!data || typeof data !== 'object' || !('value' in data)) {
79
+ return fail(settingsError(`unexpected response from crtr sys config set ${key}`));
80
+ }
81
+ return ok(/** @type {unknown} */ (data).value);
82
+ },
83
+ };
84
+ }
85
+
86
+ /** @typedef {{ kind:'defaultProvider' } | { kind:'matrix'; strength:ModelStrength } | { kind:'persona'; persona:string } | { kind:'addPersona' }} Row */
87
+
88
+ /** @typedef {Object} EditState
89
+ * @property {'defaultProvider'|'matrixCell'|'personaStrength'|'personaNew'} kind
90
+ * @property {string} draft
91
+ * @property {string} value
92
+ * @property {string} label
93
+ * @property {ModelStrength} [strength]
94
+ * @property {ModelProvider} [provider]
95
+ * @property {string} [persona]
96
+ */
97
+
98
+ /** @typedef {Object} SettingsState
99
+ * @property {ModelLaddersConfig|null} modelLadders
100
+ * @property {Record<string, ModelStrength>} personaStrengths
101
+ * @property {Record<ModelStrength, ModelProvider>} matrixSelection
102
+ * @property {number} cursor
103
+ * @property {number} scroll
104
+ * @property {number} lastFetch
105
+ * @property {SourceError|null} sourceError
106
+ * @property {EditState|null} edit
107
+ */
108
+
109
+ /** @param {SettingsState} state @returns {Row[]} */
110
+ export function buildRows(state) {
111
+ if (!state.modelLadders) return [];
112
+ const rows = [{ kind: 'defaultProvider' }];
113
+ for (const strength of STRENGTHS) rows.push({ kind: 'matrix', strength });
114
+ for (const persona of Object.keys(state.personaStrengths).sort((a, b) => a.localeCompare(b))) rows.push({ kind: 'persona', persona });
115
+ rows.push({ kind: 'addPersona' });
116
+ return rows;
117
+ }
118
+
119
+ /** @param {SettingsState} state @returns {number} */
120
+ function cursorClamp(state) {
121
+ const rows = buildRows(state);
122
+ return rows.length === 0 ? 0 : Math.min(state.cursor, rows.length - 1);
123
+ }
124
+
125
+ /** @param {SettingsState} state @returns {Row|undefined} */
126
+ function currentRow(state) {
127
+ return buildRows(state)[cursorClamp(state)];
128
+ }
129
+
130
+ /** @param {SettingsState} state @param {Row|undefined} row @returns {string} */
131
+ export function settingsRowLabel(state, row) {
132
+ if (!row) return '';
133
+ if (row.kind === 'defaultProvider') return 'Default provider';
134
+ if (row.kind === 'matrix') return `${row.strength} strength`;
135
+ if (row.kind === 'persona') return row.persona;
136
+ return 'Add persona strength';
137
+ }
138
+
139
+ /** @param {string} draft @returns {ModelStrength | null} */
140
+ function parseStrength(draft) {
141
+ const s = draft.trim();
142
+ return s === 'ultra' || s === 'strong' || s === 'medium' || s === 'light' ? s : null;
143
+ }
144
+
145
+ /** @param {string} draft @returns {{persona:string, strength:ModelStrength}|null} */
146
+ function parsePersonaPair(draft) {
147
+ const s = draft.trim();
148
+ if (!s) return null;
149
+ const eq = s.indexOf('=');
150
+ if (eq > 0) {
151
+ const persona = s.slice(0, eq).trim();
152
+ const strength = parseStrength(s.slice(eq + 1));
153
+ return persona && strength ? { persona, strength } : null;
154
+ }
155
+ const parts = s.split(/\s+/).filter(Boolean);
156
+ if (parts.length >= 2) {
157
+ const strength = parseStrength(parts[parts.length - 1] || '');
158
+ const persona = parts.slice(0, -1).join(' ').trim();
159
+ return persona && strength ? { persona, strength } : null;
160
+ }
161
+ return null;
162
+ }
163
+
164
+ /** @param {SettingsState} state @param {Row} row @returns {{ kind:'defaultProvider'|'matrixCell'|'personaStrength'|'personaNew', draft:string, value:string, label:string, strength?:ModelStrength, provider?:ModelProvider, persona?:string }} */
165
+ export function settingsTargetForRow(state, row) {
166
+ if (row.kind === 'defaultProvider') {
167
+ return { kind: 'defaultProvider', draft: '', value: state.modelLadders?.defaultProvider ?? 'anthropic', label: 'default provider' };
168
+ }
169
+ if (row.kind === 'matrix') {
170
+ const provider = state.matrixSelection[row.strength] ?? DEFAULT_MATRIX_SELECTION[row.strength];
171
+ return {
172
+ kind: 'matrixCell',
173
+ strength: row.strength,
174
+ provider,
175
+ draft: '',
176
+ value: state.modelLadders?.[provider]?.[row.strength] ?? '',
177
+ label: `${provider} / ${row.strength}`,
178
+ };
179
+ }
180
+ if (row.kind === 'persona') {
181
+ return { kind: 'personaStrength', persona: row.persona, draft: '', value: state.personaStrengths[row.persona] ?? 'strong', label: row.persona };
182
+ }
183
+ return { kind: 'personaNew', draft: '', value: '', label: 'new persona strength' };
184
+ }
185
+
186
+ /** @param {Ctx} ctx @returns {Promise<{ok:true, data:{ladders: ModelLaddersConfig, personaStrengths: Record<string, ModelStrength>}} | {ok:false, error:SourceError}>} */
187
+ async function loadConfig(ctx) {
188
+ const [ladders, personaStrengths] = await Promise.all([
189
+ ctx.resolve(makeConfigGetSource('modelLadders')),
190
+ ctx.resolve(makeConfigGetSource('personaStrengths')),
191
+ ]);
192
+ if (!ladders.ok) return ladders;
193
+ if (!personaStrengths.ok) return personaStrengths;
194
+ return ok({ ladders: /** @type {ModelLaddersConfig} */ (ladders.data), personaStrengths: /** @type {Record<string, ModelStrength>} */ (personaStrengths.data) });
195
+ }
196
+
197
+ /** @param {Ctx} ctx @param {string} msg @param {SourceError['display']['level']} [level='error'] */
198
+ function setBanner(ctx, msg, level = 'error') {
199
+ if (level === 'info') ctx.signal.setStatus(msg);
200
+ else ctx.signal.setBanner(msg, level);
201
+ }
202
+
203
+ /** @typedef {{ kind:'defaultProvider'|'matrixCell'|'personaStrength'|'personaNew', value:string, strength?:ModelStrength, provider?:ModelProvider, persona?:string }} PersistTarget */
204
+
205
+ /** Validate a target, write it via `crtr sys config set`, fold the result into
206
+ * local state, and re-pull. Shared by submitEdit (text fields) and applyValue
207
+ * (one-click enum chips on web). Returns false on validation/transport failure
208
+ * (a banner is already set). @param {Ctx} ctx @param {PersistTarget} target */
209
+ async function persist(ctx, target) {
210
+ const value = String(target.value ?? '').trim();
211
+ if (target.kind === 'defaultProvider') {
212
+ if (value !== 'anthropic' && value !== 'openai') { setBanner(ctx, 'default provider must be anthropic or openai', 'action'); return false; }
213
+ } else if (target.kind === 'matrixCell') {
214
+ if (!value) { setBanner(ctx, 'model id cannot be empty', 'action'); return false; }
215
+ } else if (target.kind === 'personaStrength') {
216
+ if (!parseStrength(value)) { setBanner(ctx, 'persona strength must be ultra, strong, medium, or light', 'action'); return false; }
217
+ } else if (target.kind === 'personaNew') {
218
+ if (!parsePersonaPair(value)) { setBanner(ctx, 'use "kind strength" or "kind=strength"', 'action'); return false; }
219
+ }
220
+
221
+ ctx.signal.setStatus('Saving…');
222
+ let key = '';
223
+ let writeValue = '';
224
+ if (target.kind === 'defaultProvider') { key = 'modelLadders.defaultProvider'; writeValue = value; }
225
+ else if (target.kind === 'matrixCell') { key = `modelLadders.${target.provider}.${target.strength}`; writeValue = value; }
226
+ else if (target.kind === 'personaStrength') { key = `personaStrengths.${target.persona}`; writeValue = value; }
227
+ else {
228
+ const pair = parsePersonaPair(value);
229
+ if (!pair) return false;
230
+ key = `personaStrengths.${pair.persona}`;
231
+ writeValue = pair.strength;
232
+ }
233
+
234
+ const r = await ctx.execute(makeConfigSetCommand(key, writeValue));
235
+ if (!r.ok) {
236
+ setBanner(ctx, r.error.display.explanation || r.error.display.headline, r.error.display.level);
237
+ ctx.signal.setStatus(null);
238
+ return false;
239
+ }
240
+ ctx.set((s) => {
241
+ const next = { ...s, edit: null };
242
+ if (target.kind === 'defaultProvider' && next.modelLadders) next.modelLadders = { ...next.modelLadders, defaultProvider: value };
243
+ if (target.kind === 'matrixCell' && next.modelLadders) next.modelLadders = { ...next.modelLadders, [target.provider]: { ...next.modelLadders[target.provider], [target.strength]: value } };
244
+ if (target.kind === 'personaStrength') next.personaStrengths = { ...next.personaStrengths, [target.persona]: /** @type {ModelStrength} */ (value) };
245
+ if (target.kind === 'personaNew') {
246
+ const pair = parsePersonaPair(value);
247
+ if (pair) next.personaStrengths = { ...next.personaStrengths, [pair.persona]: pair.strength };
248
+ }
249
+ return next;
250
+ });
251
+ ctx.signal.setStatus('Saved');
252
+ await ctx.dispatch('refresh');
253
+ return true;
254
+ }
255
+
256
+ /** @type {import('../../core/view/contract.js').ViewCore<SettingsState>} */
257
+ const core = {
258
+ manifest: {
259
+ id: 'settings',
260
+ title: 'Model Ladders',
261
+ subtitle: 'provider × strength matrix and persona strengths',
262
+ description: 'edit model ladders and personaStrengths through crtr commands',
263
+ },
264
+
265
+ init() {
266
+ return {
267
+ modelLadders: null,
268
+ personaStrengths: {},
269
+ matrixSelection: { ...DEFAULT_MATRIX_SELECTION },
270
+ cursor: 0,
271
+ scroll: 0,
272
+ lastFetch: 0,
273
+ sourceError: null,
274
+ edit: null,
275
+ };
276
+ },
277
+
278
+ sources: {
279
+ modelLadders: makeConfigGetSource('modelLadders'),
280
+ personaStrengths: makeConfigGetSource('personaStrengths'),
281
+ },
282
+
283
+ intents: {
284
+ async refresh(ctx) {
285
+ ctx.signal.setStatus('Loading settings…');
286
+ const r = await loadConfig(ctx);
287
+ if (!r.ok) {
288
+ if (ctx.state.lastFetch === 0 || ctx.state.modelLadders === null) {
289
+ ctx.set((s) => ({ ...s, sourceError: r.error, lastFetch: Date.now() }));
290
+ } else {
291
+ setBanner(ctx, r.error.display.explanation || r.error.display.headline, r.error.display.level);
292
+ }
293
+ ctx.signal.setStatus(null);
294
+ return;
295
+ }
296
+ ctx.set((s) => {
297
+ const next = {
298
+ ...s,
299
+ modelLadders: r.data.ladders,
300
+ personaStrengths: r.data.personaStrengths,
301
+ sourceError: null,
302
+ lastFetch: Date.now(),
303
+ };
304
+ return { ...next, cursor: Math.min(next.cursor, Math.max(0, buildRows(next).length - 1)) };
305
+ });
306
+ ctx.signal.clearBanner();
307
+ ctx.signal.setStatus(null);
308
+ },
309
+
310
+ cursorDown: (ctx) => ctx.set((s) => ({ ...s, cursor: Math.min(Math.max(0, buildRows(s).length - 1), s.cursor + 1) })),
311
+ cursorUp: (ctx) => ctx.set((s) => ({ ...s, cursor: Math.max(0, s.cursor - 1) })),
312
+
313
+ matrixLeft: (ctx) => ctx.set((s) => {
314
+ const row = currentRow(s);
315
+ if (!row || row.kind !== 'matrix') return s;
316
+ return { ...s, matrixSelection: { ...s.matrixSelection, [row.strength]: 'anthropic' } };
317
+ }),
318
+ matrixRight: (ctx) => ctx.set((s) => {
319
+ const row = currentRow(s);
320
+ if (!row || row.kind !== 'matrix') return s;
321
+ return { ...s, matrixSelection: { ...s.matrixSelection, [row.strength]: 'openai' } };
322
+ }),
323
+
324
+ beginEdit: (ctx) => ctx.set((s) => {
325
+ const row = currentRow(s);
326
+ if (!row || s.modelLadders === null) return s;
327
+ const target = settingsTargetForRow(s, row);
328
+ return { ...s, edit: { ...target } };
329
+ }),
330
+
331
+ // Open the editor for a SPECIFIC target named by the click (web mouse path),
332
+ // prefilling the draft with the current value so it edits in place. Unlike
333
+ // beginEdit it does not depend on cursor / matrixSelection.
334
+ beginEditFor: (ctx, payload) => ctx.set((s) => {
335
+ if (s.modelLadders === null) return s;
336
+ const p = payload && typeof payload === 'object' ? /** @type {Record<string, unknown>} */ (payload) : {};
337
+ if (p.kind === 'matrix' && typeof p.strength === 'string') {
338
+ const provider = p.provider === 'openai' ? 'openai' : 'anthropic';
339
+ const cur = s.modelLadders?.[provider]?.[/** @type {ModelStrength} */ (p.strength)] ?? '';
340
+ return { ...s, edit: { kind: 'matrixCell', strength: /** @type {ModelStrength} */ (p.strength), provider, draft: cur, value: cur, label: `${provider} / ${p.strength}` } };
341
+ }
342
+ if (p.kind === 'defaultProvider') {
343
+ const cur = s.modelLadders.defaultProvider ?? 'anthropic';
344
+ return { ...s, edit: { kind: 'defaultProvider', draft: cur, value: cur, label: 'default provider' } };
345
+ }
346
+ if (p.kind === 'persona' && typeof p.persona === 'string') {
347
+ const cur = s.personaStrengths[p.persona] ?? 'strong';
348
+ return { ...s, edit: { kind: 'personaStrength', persona: p.persona, draft: cur, value: cur, label: p.persona } };
349
+ }
350
+ return { ...s, edit: { kind: 'personaNew', draft: '', value: '', label: 'new persona strength' } };
351
+ }),
352
+
353
+ setDraft: (ctx, draft) => ctx.set((s) => (s.edit ? { ...s, edit: { ...s.edit, draft: typeof draft === 'string' ? draft : '' } } : s)),
354
+
355
+ cancelEdit: (ctx) => ctx.set((s) => (s.edit ? { ...s, edit: null } : s)),
356
+
357
+ async submitEdit(ctx) {
358
+ const edit = ctx.state.edit;
359
+ if (!edit) return;
360
+ await persist(ctx, { kind: edit.kind, value: edit.draft, strength: edit.strength, provider: edit.provider, persona: edit.persona });
361
+ },
362
+
363
+ // One-click save for enum fields (web chips): no editor round-trip. Payload
364
+ // is a fully-specified PersistTarget.
365
+ async applyValue(ctx, payload) {
366
+ const p = payload && typeof payload === 'object' ? /** @type {PersistTarget} */ (payload) : null;
367
+ if (!p || ctx.state.modelLadders === null) return;
368
+ await persist(ctx, p);
369
+ },
370
+
371
+ jumpAddPersona: (ctx) => ctx.set((s) => ({ ...s, cursor: Math.max(0, buildRows(s).length - 1) })),
372
+
373
+ selectRow: (ctx, payload) => ctx.set((s) => {
374
+ const p = payload && typeof payload === 'object' ? /** @type {Record<string, unknown>} */ (payload) : {};
375
+ const rows = buildRows(s);
376
+ const target = rows.findIndex((row) => {
377
+ if (row.kind === 'defaultProvider' && p.kind === 'defaultProvider') return true;
378
+ if (row.kind === 'matrix' && p.kind === 'matrix' && p.strength === row.strength) return true;
379
+ if (row.kind === 'persona' && p.kind === 'persona' && p.persona === row.persona) return true;
380
+ if (row.kind === 'addPersona' && p.kind === 'addPersona') return true;
381
+ return false;
382
+ });
383
+ if (target < 0) return s;
384
+ if (p.kind === 'matrix' && (p.provider === 'anthropic' || p.provider === 'openai') && typeof p.strength === 'string') {
385
+ return { ...s, cursor: target, matrixSelection: { ...s.matrixSelection, [/** @type {ModelStrength} */ (p.strength)]: /** @type {ModelProvider} */ (p.provider) } };
386
+ }
387
+ return { ...s, cursor: target };
388
+ }),
389
+
390
+ quit: (ctx) => ctx.signal.quit(),
391
+ },
392
+ };
393
+
394
+ export const configGetSource = makeConfigGetSource;
395
+ export const configSetCommand = makeConfigSetCommand;
396
+
397
+ export default core;
@@ -0,0 +1,40 @@
1
+ // @ts-check
2
+ /**
3
+ * Model ladders settings — text presenter for the `settings` view.
4
+ *
5
+ * @module settings/text
6
+ */
7
+
8
+ import { buildRows } from './core.mjs';
9
+
10
+ /** @typedef {import('./core.mjs').SettingsState} SettingsState */
11
+
12
+ /** @param {SettingsState} state @param {import('../../core/view/contract.js').DumpContext} [ctx] @returns {string} */
13
+ export function dump(state, ctx) {
14
+ const lines = ['Model ladders'];
15
+ if (ctx && ctx.banner) lines.push('', `[${ctx.banner.level}] ${ctx.banner.msg}`);
16
+ else if (state.sourceError) lines.push('', `[${state.sourceError.display.level}] ${state.sourceError.display.explanation}`);
17
+ lines.push('', 'Provider × strength matrix', '');
18
+ if (state.sourceError && state.modelLadders === null) {
19
+ const d = state.sourceError.display;
20
+ return ['Model ladders', '', `[${d.level}] ${d.headline}`, d.explanation, d.nextStep].filter(Boolean).join('\n');
21
+ }
22
+ if (state.modelLadders === null) return lines.concat(['(loading…)']).join('\n');
23
+ for (const row of buildRows(state)) {
24
+ if (row.kind === 'defaultProvider') {
25
+ lines.push(`default provider: ${state.modelLadders.defaultProvider ?? 'anthropic'}`);
26
+ continue;
27
+ }
28
+ if (row.kind === 'matrix') {
29
+ const provider = state.matrixSelection[row.strength] ?? 'anthropic';
30
+ lines.push(`${row.strength}: anthropic=${state.modelLadders.anthropic?.[row.strength] ?? '—'} | openai=${state.modelLadders.openai?.[row.strength] ?? '—'}${provider ? ` [selected ${provider}]` : ''}`);
31
+ continue;
32
+ }
33
+ if (row.kind === 'persona') {
34
+ lines.push(`${row.persona}: ${state.personaStrengths[row.persona] ?? 'strong'}`);
35
+ continue;
36
+ }
37
+ lines.push('+ add persona strength');
38
+ }
39
+ return lines.join('\n');
40
+ }
@@ -0,0 +1,95 @@
1
+ // @ts-check
2
+ /**
3
+ * Model ladders settings — TUI presenter for the `settings` view.
4
+ *
5
+ * @module settings/tui
6
+ */
7
+
8
+ import { loadingState, notReadyState } from '../_lib/states.mjs';
9
+ import { buildRows, settingsRowLabel, settingsTargetForRow } from './core.mjs';
10
+
11
+ /** @typedef {import('./core.mjs').SettingsState} SettingsState */
12
+
13
+ /** @param {SettingsState} state @returns {import('../../core/tui/draw.js').ListItemRow[]} */
14
+ function rows(state) {
15
+ const out = [];
16
+ const dataRows = buildRows(state);
17
+ for (const row of dataRows) {
18
+ if (row.kind === 'defaultProvider') {
19
+ const value = state.modelLadders?.defaultProvider ?? 'anthropic';
20
+ out.push({ spans: [{ text: 'Default provider', style: { bold: true } }, { text: ' ' }, { text: value, style: { fg: '36' } }] });
21
+ continue;
22
+ }
23
+ if (row.kind === 'matrix') {
24
+ const selected = state.matrixSelection[row.strength] ?? 'anthropic';
25
+ const a = state.modelLadders?.anthropic?.[row.strength] ?? '—';
26
+ const o = state.modelLadders?.openai?.[row.strength] ?? '—';
27
+ out.push({
28
+ spans: [
29
+ { text: row.strength, style: { bold: true } },
30
+ { text: ' ' },
31
+ { text: 'anthropic: ', style: { dim: true } },
32
+ { text: a, style: selected === 'anthropic' ? { reverse: true, bold: true } : undefined },
33
+ { text: ' ' },
34
+ { text: 'openai: ', style: { dim: true } },
35
+ { text: o, style: selected === 'openai' ? { reverse: true, bold: true } : undefined },
36
+ ],
37
+ });
38
+ continue;
39
+ }
40
+ if (row.kind === 'persona') {
41
+ out.push({ spans: [{ text: row.persona, style: { bold: true } }, { text: ' → ' }, { text: state.personaStrengths[row.persona] ?? 'strong', style: { fg: '33' } }] });
42
+ continue;
43
+ }
44
+ out.push({ spans: [{ text: '+ add persona strength', style: { fg: '32', bold: true } }] });
45
+ }
46
+ return out;
47
+ }
48
+
49
+ /** @param {SettingsState} state @param {import('../../core/tui/draw.js').Draw} draw @param {import('../../core/tui/draw.js').Rect} content */
50
+ export function render(state, draw, content) {
51
+ if (content.width <= 0 || content.height <= 0) return;
52
+ if (state.sourceError && state.modelLadders === null) {
53
+ const d = state.sourceError.display;
54
+ notReadyState(draw, content, {
55
+ glyph: d.level === 'action' ? '⊙' : '⚠',
56
+ glyphFg: d.level === 'action' ? '33' : '31',
57
+ headline: d.headline,
58
+ explanation: d.explanation,
59
+ nextStep: d.nextStep,
60
+ });
61
+ return;
62
+ }
63
+ if (state.modelLadders === null) {
64
+ loadingState(draw, content, { rows: Math.min(5, content.height), label: 'Loading model ladders…' });
65
+ return;
66
+ }
67
+
68
+ const header = state.edit
69
+ ? `Replacing ${state.edit.label} — Enter saves, Esc cancels`
70
+ : 'j/k move · h/l switch matrix cell · enter edit · n add persona · g refresh';
71
+ draw.text(content.row, content.col, 'Model ladders', { bold: true });
72
+ draw.text(content.row + 1, content.col, header, { dim: true });
73
+ if (state.edit) {
74
+ draw.text(content.row + 2, content.col, `Current: ${state.edit.value || '(empty)'}`, { dim: true });
75
+ draw.text(content.row + 3, content.col, `Replacement: ${state.edit.draft}`, { fg: '33' });
76
+ }
77
+ const listRect = { row: content.row + (state.edit ? 4 : 3), col: content.col, width: content.width, height: Math.max(0, content.height - (state.edit ? 4 : 3)) };
78
+ const items = rows(state);
79
+ const res = draw.list(listRect, items, state.cursor, state.scroll);
80
+ state.scroll = res.scroll;
81
+ }
82
+
83
+ export const keymap = [
84
+ { keys: ['j', 'down'], intent: 'cursorDown', when: (s) => !s.edit, hint: { keys: 'j/k', label: 'move' } },
85
+ { keys: ['k', 'up'], intent: 'cursorUp', when: (s) => !s.edit },
86
+ { keys: ['h', 'left'], intent: 'matrixLeft', when: (s) => !s.edit, hint: { keys: 'h/l', label: 'switch cell' } },
87
+ { keys: ['l', 'right'], intent: 'matrixRight', when: (s) => !s.edit },
88
+ { keys: ['n'], intent: 'jumpAddPersona', when: (s) => !s.edit, hint: { keys: 'n', label: 'add persona' } },
89
+ { keys: ['g'], intent: 'refresh', when: (s) => !s.edit, hint: { keys: 'g', label: 'refresh' } },
90
+ { keys: ['q'], intent: 'quit', hint: { keys: 'q', label: 'quit' } },
91
+ { capture: 'setDraft', when: (s) => !!s.edit },
92
+ { keys: ['enter', 'return'], intent: 'submitEdit', when: (s) => !!s.edit },
93
+ { keys: ['enter', 'return'], intent: 'beginEdit', when: (s) => !s.edit, hint: { keys: 'enter', label: 'edit' } },
94
+ { keys: ['escape', 'esc'], intent: 'cancelEdit', when: (s) => !!s.edit },
95
+ ];