@crouton-kit/crouter 0.3.27 → 0.3.29

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 (343) hide show
  1. package/dist/build-root.js +4 -2
  2. package/dist/builtin-memory/crouter-development/marketplaces.md +7 -6
  3. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +1 -1
  4. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +1 -1
  5. package/dist/builtin-memory/crouter-development/personas.md +1 -1
  6. package/dist/builtin-memory/crouter-development/plugins.md +20 -18
  7. package/dist/builtin-memory/design.md +1 -1
  8. package/dist/builtin-memory/development.md +1 -1
  9. package/dist/builtin-memory/internal/INDEX.md +1 -1
  10. package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
  11. package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
  12. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  13. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  14. package/dist/builtin-memory/planning.md +1 -1
  15. package/dist/builtin-memory/spec.md +6 -4
  16. package/dist/builtin-personas/orchestration-kernel.md +4 -5
  17. package/dist/builtin-personas/runtime-base.md +8 -4
  18. package/dist/builtin-personas/spec/PERSONA.md +8 -4
  19. package/dist/builtin-personas/spec/orchestrator.md +5 -3
  20. package/dist/builtin-personas/spec/requirements/PERSONA.md +10 -0
  21. package/dist/builtin-views/canvas/core.mjs +586 -0
  22. package/dist/builtin-views/canvas/text.mjs +58 -0
  23. package/dist/builtin-views/canvas/tui.mjs +165 -0
  24. package/dist/builtin-views/canvas/web.jsx +120 -0
  25. package/dist/builtin-views/git-pr/core.mjs +673 -0
  26. package/dist/builtin-views/git-pr/text.mjs +84 -0
  27. package/dist/builtin-views/git-pr/tui.mjs +302 -0
  28. package/dist/builtin-views/git-pr/web.jsx +216 -0
  29. package/dist/builtin-views/inbox/_lib/render.mjs +1 -3
  30. package/dist/builtin-views/inbox/core.mjs +1273 -0
  31. package/dist/builtin-views/inbox/text.mjs +73 -0
  32. package/dist/builtin-views/inbox/tui.mjs +312 -0
  33. package/dist/builtin-views/inbox/web.jsx +188 -0
  34. package/dist/builtin-views/linkedin/core.mjs +906 -0
  35. package/dist/builtin-views/linkedin/text.mjs +69 -0
  36. package/dist/builtin-views/linkedin/tui.mjs +427 -0
  37. package/dist/builtin-views/linkedin/web.jsx +206 -0
  38. package/dist/builtin-views/workspace-sidebar/core.mjs +621 -0
  39. package/dist/builtin-views/workspace-sidebar/text.mjs +53 -0
  40. package/dist/builtin-views/workspace-sidebar/tui.mjs +142 -0
  41. package/dist/builtin-views/workspace-sidebar/web.jsx +109 -0
  42. package/dist/cli.js +3 -3
  43. package/dist/clients/attach/__tests__/action-parity.test.js +48 -0
  44. package/dist/clients/attach/__tests__/clipboard-image.test.js +76 -0
  45. package/dist/clients/attach/__tests__/editor-newline.test.js +57 -0
  46. package/dist/clients/attach/__tests__/git-info.test.js +31 -0
  47. package/dist/clients/attach/__tests__/onrequest-wired.test.js +20 -0
  48. package/dist/clients/attach/__tests__/reconnect-giveup.test.js +30 -0
  49. package/dist/clients/attach/__tests__/slash-quit-copy.test.js +42 -0
  50. package/dist/clients/attach/__tests__/titled-editor.test.d.ts +1 -0
  51. package/dist/clients/attach/__tests__/titled-editor.test.js +39 -0
  52. package/dist/clients/attach/attach-cmd.js +445 -41
  53. package/dist/clients/attach/auth-pickers.d.ts +9 -0
  54. package/dist/clients/attach/auth-pickers.js +194 -0
  55. package/dist/clients/attach/canvas-panels.d.ts +12 -0
  56. package/dist/clients/attach/canvas-panels.js +78 -0
  57. package/dist/clients/attach/chat-view.d.ts +27 -2
  58. package/dist/clients/attach/chat-view.js +98 -9
  59. package/dist/clients/attach/clipboard-image.d.ts +47 -8
  60. package/dist/clients/attach/clipboard-image.js +150 -26
  61. package/dist/clients/attach/clipboard-text.d.ts +3 -0
  62. package/dist/clients/attach/clipboard-text.js +39 -0
  63. package/dist/clients/attach/config-load.d.ts +54 -7
  64. package/dist/clients/attach/config-load.js +99 -3
  65. package/dist/clients/attach/context-message.d.ts +12 -0
  66. package/dist/clients/attach/context-message.js +72 -0
  67. package/dist/clients/attach/git-info.d.ts +20 -0
  68. package/dist/clients/attach/git-info.js +44 -0
  69. package/dist/clients/attach/graph-overlay.d.ts +43 -0
  70. package/dist/clients/attach/graph-overlay.js +306 -0
  71. package/dist/clients/attach/input-controller.d.ts +81 -13
  72. package/dist/clients/attach/input-controller.js +307 -67
  73. package/dist/clients/attach/pickers.d.ts +58 -0
  74. package/dist/clients/attach/pickers.js +171 -0
  75. package/dist/clients/attach/slash-commands.d.ts +44 -1
  76. package/dist/clients/attach/slash-commands.js +250 -27
  77. package/dist/clients/attach/titled-editor.d.ts +33 -0
  78. package/dist/clients/attach/titled-editor.js +84 -0
  79. package/dist/clients/attach/view-socket.d.ts +37 -2
  80. package/dist/clients/attach/view-socket.js +131 -7
  81. package/dist/clients/web/dev-server.d.ts +7 -0
  82. package/dist/clients/web/dev-server.js +59 -0
  83. package/dist/clients/web/events.d.ts +14 -0
  84. package/dist/clients/web/events.js +151 -0
  85. package/dist/clients/web/server.d.ts +18 -0
  86. package/dist/clients/web/server.js +450 -0
  87. package/dist/clients/web/web-cmd.d.ts +2 -0
  88. package/dist/clients/web/web-cmd.js +120 -0
  89. package/dist/commands/canvas.js +1 -2
  90. package/dist/commands/chord.js +1 -1
  91. package/dist/commands/dashboard.js +5 -1
  92. package/dist/commands/human/prompts.js +3 -3
  93. package/dist/commands/human/queue.d.ts +17 -0
  94. package/dist/commands/human/queue.js +111 -4
  95. package/dist/commands/memory/__tests__/lint-schema.test.js +27 -4
  96. package/dist/commands/memory/lint.d.ts +5 -4
  97. package/dist/commands/memory/lint.js +23 -7
  98. package/dist/commands/memory/read.js +2 -2
  99. package/dist/commands/memory/shared.d.ts +7 -1
  100. package/dist/commands/memory/shared.js +18 -3
  101. package/dist/commands/memory/write.js +20 -7
  102. package/dist/commands/memory.js +4 -4
  103. package/dist/commands/node.d.ts +1 -1
  104. package/dist/commands/node.js +64 -65
  105. package/dist/commands/pkg.js +1 -2
  106. package/dist/commands/revive.js +11 -3
  107. package/dist/commands/sys/feedback.d.ts +1 -0
  108. package/dist/commands/sys/feedback.js +163 -0
  109. package/dist/commands/sys/sync.d.ts +1 -0
  110. package/dist/commands/sys/sync.js +187 -0
  111. package/dist/commands/sys.js +4 -2
  112. package/dist/commands/view-cycle.js +2 -2
  113. package/dist/commands/view-list.js +8 -8
  114. package/dist/commands/view-new.js +21 -17
  115. package/dist/commands/view-pick.js +1 -1
  116. package/dist/commands/view-run.js +35 -14
  117. package/dist/commands/view.js +8 -6
  118. package/dist/commands/workspace.d.ts +2 -0
  119. package/dist/commands/workspace.js +161 -0
  120. package/dist/core/__tests__/broker-double-spawn.test.d.ts +1 -0
  121. package/dist/core/__tests__/broker-double-spawn.test.js +143 -0
  122. package/dist/core/__tests__/broker-fork-seam.test.d.ts +1 -0
  123. package/dist/core/__tests__/broker-fork-seam.test.js +102 -0
  124. package/dist/core/__tests__/broker-sdk-wiring.test.js +2 -0
  125. package/dist/core/__tests__/broker-snapshot-history.test.d.ts +1 -0
  126. package/dist/core/__tests__/broker-snapshot-history.test.js +105 -0
  127. package/dist/core/__tests__/child-death-wake.test.js +56 -111
  128. package/dist/core/__tests__/close.test.js +14 -20
  129. package/dist/core/__tests__/context-intro.test.js +19 -19
  130. package/dist/core/__tests__/daemon-boot.test.js +30 -23
  131. package/dist/core/__tests__/draw-style.test.js +1 -1
  132. package/dist/core/__tests__/error-stall-recycle.test.d.ts +1 -0
  133. package/dist/core/__tests__/error-stall-recycle.test.js +141 -0
  134. package/dist/core/__tests__/fixtures/fake-engine.d.ts +24 -1
  135. package/dist/core/__tests__/fixtures/fake-engine.js +32 -2
  136. package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
  137. package/dist/core/__tests__/focuses.test.js +25 -13
  138. package/dist/core/__tests__/fork.test.js +22 -5
  139. package/dist/core/__tests__/full/broker-control-preempt.test.d.ts +1 -0
  140. package/dist/core/__tests__/full/broker-control-preempt.test.js +61 -0
  141. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +1 -0
  142. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +57 -0
  143. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +1 -0
  144. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +80 -0
  145. package/dist/core/__tests__/full/broker-pane-resolution.test.js +90 -0
  146. package/dist/core/__tests__/full/cascade-close.test.js +22 -8
  147. package/dist/core/__tests__/full/detach-focus.test.js +66 -169
  148. package/dist/core/__tests__/helpers/harness.d.ts +6 -9
  149. package/dist/core/__tests__/helpers/harness.js +19 -36
  150. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +1 -0
  151. package/dist/core/__tests__/human-node-not-supervised.test.js +83 -0
  152. package/dist/core/__tests__/human-stranded-deliver.test.d.ts +1 -0
  153. package/dist/core/__tests__/human-stranded-deliver.test.js +108 -0
  154. package/dist/core/__tests__/lifecycle.test.js +1 -19
  155. package/dist/core/__tests__/live-mutation-verbs.test.js +5 -5
  156. package/dist/core/__tests__/memory-resolver.test.js +1 -1
  157. package/dist/core/__tests__/on-read-dedup-resume.test.d.ts +1 -0
  158. package/dist/core/__tests__/on-read-dedup-resume.test.js +81 -0
  159. package/dist/core/__tests__/refresh-stall-recycle.test.d.ts +1 -0
  160. package/dist/core/__tests__/refresh-stall-recycle.test.js +88 -0
  161. package/dist/core/__tests__/relaunch-root.test.d.ts +1 -0
  162. package/dist/core/__tests__/relaunch-root.test.js +114 -0
  163. package/dist/core/__tests__/reset.test.js +19 -79
  164. package/dist/core/__tests__/steer-note.test.js +9 -7
  165. package/dist/core/__tests__/tmux-surface.test.js +13 -7
  166. package/dist/core/bootstrap.d.ts +0 -3
  167. package/dist/core/bootstrap.js +1 -143
  168. package/dist/core/canvas/browse/__tests__/model.test.js +86 -1
  169. package/dist/core/canvas/browse/__tests__/render.test.js +2 -1
  170. package/dist/core/canvas/browse/app.js +131 -8
  171. package/dist/core/canvas/browse/model.d.ts +23 -5
  172. package/dist/core/canvas/browse/model.js +68 -13
  173. package/dist/core/canvas/browse/render.d.ts +7 -1
  174. package/dist/core/canvas/browse/render.js +178 -47
  175. package/dist/core/canvas/canvas.js +1 -1
  176. package/dist/core/canvas/focuses.d.ts +4 -4
  177. package/dist/core/canvas/focuses.js +7 -7
  178. package/dist/core/canvas/nav-model.d.ts +162 -0
  179. package/dist/core/canvas/nav-model.js +487 -0
  180. package/dist/core/canvas/paths.d.ts +7 -0
  181. package/dist/core/canvas/paths.js +9 -0
  182. package/dist/core/canvas/render.d.ts +68 -9
  183. package/dist/core/canvas/render.js +195 -61
  184. package/dist/core/canvas/types.d.ts +16 -23
  185. package/dist/core/config.js +1 -4
  186. package/dist/core/memory-resolver.js +43 -5
  187. package/dist/core/runtime/bearings.d.ts +1 -1
  188. package/dist/core/runtime/bearings.js +8 -8
  189. package/dist/core/runtime/branded-host.d.ts +16 -0
  190. package/dist/core/runtime/branded-host.js +127 -0
  191. package/dist/core/runtime/broker-protocol.d.ts +212 -6
  192. package/dist/core/runtime/broker-sdk.d.ts +0 -12
  193. package/dist/core/runtime/broker-sdk.js +77 -6
  194. package/dist/core/runtime/broker.d.ts +5 -1
  195. package/dist/core/runtime/broker.js +520 -59
  196. package/dist/core/runtime/close.d.ts +12 -2
  197. package/dist/core/runtime/close.js +37 -16
  198. package/dist/core/runtime/front-door.js +14 -7
  199. package/dist/core/runtime/host.d.ts +14 -34
  200. package/dist/core/runtime/host.js +14 -50
  201. package/dist/core/runtime/launch.d.ts +12 -9
  202. package/dist/core/runtime/launch.js +27 -15
  203. package/dist/core/runtime/lifecycle.d.ts +1 -1
  204. package/dist/core/runtime/lifecycle.js +15 -19
  205. package/dist/core/runtime/nodes.d.ts +0 -55
  206. package/dist/core/runtime/nodes.js +6 -74
  207. package/dist/core/runtime/placement.d.ts +91 -334
  208. package/dist/core/runtime/placement.js +262 -828
  209. package/dist/core/runtime/promote.d.ts +2 -0
  210. package/dist/core/runtime/promote.js +24 -6
  211. package/dist/core/runtime/recap.d.ts +8 -0
  212. package/dist/core/runtime/recap.js +107 -0
  213. package/dist/core/runtime/recycle.js +25 -61
  214. package/dist/core/runtime/reset.d.ts +43 -37
  215. package/dist/core/runtime/reset.js +131 -218
  216. package/dist/core/runtime/revive.d.ts +9 -29
  217. package/dist/core/runtime/revive.js +45 -135
  218. package/dist/core/runtime/spawn.d.ts +15 -11
  219. package/dist/core/runtime/spawn.js +168 -136
  220. package/dist/core/runtime/surface-bg.d.ts +11 -0
  221. package/dist/core/runtime/surface-bg.js +68 -0
  222. package/dist/core/runtime/tmux.d.ts +15 -43
  223. package/dist/core/runtime/tmux.js +38 -80
  224. package/dist/core/scope.d.ts +1 -2
  225. package/dist/core/scope.js +1 -5
  226. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts +1 -0
  227. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +57 -0
  228. package/dist/core/skill-sync/builtins.d.ts +42 -0
  229. package/dist/core/skill-sync/builtins.js +112 -0
  230. package/dist/core/skill-sync/claude-plugins.d.ts +23 -0
  231. package/dist/core/skill-sync/claude-plugins.js +71 -0
  232. package/dist/core/skill-sync/engine.d.ts +42 -0
  233. package/dist/core/skill-sync/engine.js +633 -0
  234. package/dist/core/skill-sync/export.d.ts +23 -0
  235. package/dist/core/skill-sync/export.js +86 -0
  236. package/dist/core/skill-sync/manifest.d.ts +64 -0
  237. package/dist/core/skill-sync/manifest.js +181 -0
  238. package/dist/core/skill-sync/profile.d.ts +76 -0
  239. package/dist/core/skill-sync/profile.js +173 -0
  240. package/dist/core/skill-sync/snapshot.d.ts +57 -0
  241. package/dist/core/skill-sync/snapshot.js +120 -0
  242. package/dist/core/spawn.d.ts +14 -0
  243. package/dist/core/spawn.js +29 -9
  244. package/dist/core/substrate/index.d.ts +2 -2
  245. package/dist/core/substrate/index.js +7 -7
  246. package/dist/core/substrate/injected-store.d.ts +10 -0
  247. package/dist/core/substrate/injected-store.js +55 -0
  248. package/dist/core/substrate/on-read.js +68 -6
  249. package/dist/core/substrate/render.d.ts +8 -11
  250. package/dist/core/substrate/render.js +29 -43
  251. package/dist/core/substrate/schema.d.ts +16 -11
  252. package/dist/core/substrate/schema.js +32 -31
  253. package/dist/core/tui/host.d.ts +12 -4
  254. package/dist/core/tui/host.js +280 -149
  255. package/dist/core/view/bridge.d.ts +10 -0
  256. package/dist/core/view/bridge.js +31 -0
  257. package/dist/core/view/chrome.d.ts +9 -0
  258. package/dist/core/view/chrome.js +22 -0
  259. package/dist/core/view/contract.d.ts +171 -0
  260. package/dist/core/view/contract.js +23 -0
  261. package/dist/core/view/loader.d.ts +31 -0
  262. package/dist/core/view/loader.js +188 -0
  263. package/dist/core/view/transport-local.d.ts +7 -0
  264. package/dist/core/view/transport-local.js +70 -0
  265. package/dist/core/view/transport.d.ts +4 -0
  266. package/dist/core/view/transport.js +15 -0
  267. package/dist/daemon/crtrd.d.ts +38 -27
  268. package/dist/daemon/crtrd.js +303 -376
  269. package/dist/daemon/manage.js +6 -1
  270. package/dist/index.js +1 -1
  271. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +28 -20
  272. package/dist/pi-extensions/canvas-context-intro.js +4 -4
  273. package/dist/pi-extensions/canvas-doc-substrate.js +29 -20
  274. package/dist/pi-extensions/canvas-nav.js +35 -385
  275. package/dist/pi-extensions/canvas-recap.d.ts +37 -0
  276. package/dist/pi-extensions/canvas-recap.js +236 -0
  277. package/dist/pi-extensions/canvas-resume.js +2 -1
  278. package/dist/pi-extensions/canvas-stophook.d.ts +15 -13
  279. package/dist/pi-extensions/canvas-stophook.js +119 -103
  280. package/dist/pi-extensions/canvas-view.js +2 -1
  281. package/dist/pi-extensions/widget-order-bus.d.ts +6 -0
  282. package/dist/pi-extensions/widget-order-bus.js +34 -0
  283. package/dist/prompts/view.d.ts +2 -2
  284. package/dist/prompts/view.js +145 -73
  285. package/dist/types.d.ts +1 -6
  286. package/dist/types.js +1 -3
  287. package/dist/web/ViewChrome.d.ts +7 -0
  288. package/dist/web/ViewChrome.js +28 -0
  289. package/dist/web/ViewPane.d.ts +39 -0
  290. package/dist/web/ViewPane.js +48 -0
  291. package/dist/web/index.d.ts +6 -0
  292. package/dist/web/index.js +16 -0
  293. package/dist/web/runtime.d.ts +39 -0
  294. package/dist/web/runtime.js +133 -0
  295. package/dist/web/states.d.ts +24 -0
  296. package/dist/web/states.js +24 -0
  297. package/dist/web/transport-http.d.ts +5 -0
  298. package/dist/web/transport-http.js +28 -0
  299. package/dist/web-client/assets/index-BUvQb4hR.css +2 -0
  300. package/dist/web-client/assets/index-ClLQXYAE.js +10 -0
  301. package/dist/web-client/index.html +13 -0
  302. package/package.json +20 -6
  303. package/dist/builtin-views/canvas/client.mjs +0 -303
  304. package/dist/builtin-views/canvas/view.mjs +0 -576
  305. package/dist/builtin-views/git-pr/client.mjs +0 -440
  306. package/dist/builtin-views/git-pr/view.mjs +0 -675
  307. package/dist/builtin-views/inbox/sources/gmail.mjs +0 -965
  308. package/dist/builtin-views/inbox/sources/linkedin.mjs +0 -427
  309. package/dist/builtin-views/inbox/view.mjs +0 -889
  310. package/dist/builtin-views/linkedin/client.mjs +0 -610
  311. package/dist/builtin-views/linkedin/view.mjs +0 -1171
  312. package/dist/commands/pkg/bridge.d.ts +0 -1
  313. package/dist/commands/pkg/bridge.js +0 -137
  314. package/dist/commands/skill/author.d.ts +0 -3
  315. package/dist/commands/skill/author.js +0 -140
  316. package/dist/commands/skill/shared.d.ts +0 -3
  317. package/dist/commands/skill/shared.js +0 -19
  318. package/dist/commands/skill.d.ts +0 -2
  319. package/dist/commands/skill.js +0 -21
  320. package/dist/commands/tmux-spread.d.ts +0 -2
  321. package/dist/commands/tmux-spread.js +0 -144
  322. package/dist/core/__tests__/full/daemon-liveness-pane.full.test.js +0 -292
  323. package/dist/core/__tests__/full/placement-focus.test.js +0 -309
  324. package/dist/core/__tests__/full/placement-reconcile.test.js +0 -212
  325. package/dist/core/__tests__/full/placement-revive.test.js +0 -238
  326. package/dist/core/__tests__/full/placement-teardown.test.js +0 -221
  327. package/dist/core/__tests__/home-session.test.js +0 -186
  328. package/dist/core/__tests__/relaunch.test.js +0 -335
  329. package/dist/core/bridge-map.d.ts +0 -19
  330. package/dist/core/bridge-map.js +0 -73
  331. package/dist/core/tui/contract.d.ts +0 -83
  332. package/dist/core/tui/contract.js +0 -8
  333. package/dist/core/tui/loader.d.ts +0 -16
  334. package/dist/core/tui/loader.js +0 -94
  335. package/dist/prompts/skill.d.ts +0 -2
  336. package/dist/prompts/skill.js +0 -650
  337. /package/dist/{core/__tests__/full/daemon-liveness-pane.full.test.d.ts → clients/attach/__tests__/action-parity.test.d.ts} +0 -0
  338. /package/dist/{core/__tests__/full/placement-focus.test.d.ts → clients/attach/__tests__/clipboard-image.test.d.ts} +0 -0
  339. /package/dist/{core/__tests__/full/placement-reconcile.test.d.ts → clients/attach/__tests__/editor-newline.test.d.ts} +0 -0
  340. /package/dist/{core/__tests__/full/placement-revive.test.d.ts → clients/attach/__tests__/git-info.test.d.ts} +0 -0
  341. /package/dist/{core/__tests__/full/placement-teardown.test.d.ts → clients/attach/__tests__/onrequest-wired.test.d.ts} +0 -0
  342. /package/dist/{core/__tests__/home-session.test.d.ts → clients/attach/__tests__/reconnect-giveup.test.d.ts} +0 -0
  343. /package/dist/{core/__tests__/relaunch.test.d.ts → clients/attach/__tests__/slash-quit-copy.test.d.ts} +0 -0
@@ -0,0 +1,165 @@
1
+ // @ts-check
2
+ /**
3
+ * Canvas Dashboard — the TUI presenter (`render` + `keymap`) for the `canvas`
4
+ * view. Node-only (it uses the host's `Draw` API + the `_lib/states.mjs` draw
5
+ * helpers).
6
+ *
7
+ * `render` is a pure read of state; keystrokes map to named intents through
8
+ * `keymap`. All state + data logic lives in `core.mjs`.
9
+ *
10
+ * VISUAL LANGUAGE (crtr-views-visual-design §2/§3/§4): hierarchy is carried by
11
+ * weight + hue + position, never boxes. The status glyph hues match `canvas
12
+ * browse`'s authoritative palette (active=green, idle=yellow, done=cyan,
13
+ * dead=red, canceled=grey; asks=bright-yellow) — "not a recolor." Per-row
14
+ * metadata (the relative age) is right-flushed via `ListItemRow.right`; secondary
15
+ * text recedes via grey+dim so it survives NO_COLOR. The four standard states
16
+ * come from `_lib/states.mjs`.
17
+ *
18
+ * @module canvas/tui
19
+ */
20
+
21
+ import { relAge } from './core.mjs';
22
+ import { loadingState, emptyState, notReadyState } from '../_lib/states.mjs';
23
+
24
+ /** @typedef {import('./core.mjs').CanvasState} CanvasState */
25
+ /** @typedef {import('./core.mjs').TreeRow} TreeRow */
26
+
27
+ /**
28
+ * Load-bearing status hue — NUMERIC SGR codes, matching `canvas browse`'s
29
+ * STATUS_COLOR exactly (active=green, idle=yellow, done=cyan, dead=red,
30
+ * canceled=grey). The design is explicit: keep these, "this is not a recolor."
31
+ * @type {Record<string,string>}
32
+ */
33
+ const STATUS_FG = {
34
+ active: '32', // green
35
+ idle: '33', // yellow
36
+ done: '36', // cyan
37
+ dead: '31', // red
38
+ canceled: '90', // grey
39
+ };
40
+
41
+ /** @param {string} status @returns {import('../../core/tui/draw.js').Style|undefined} */
42
+ function glyphStyle(status) {
43
+ const fg = STATUS_FG[status];
44
+ return fg ? { fg } : undefined; // hue only — the glyph SHAPE is the mono carrier
45
+ }
46
+
47
+ /**
48
+ * Name weight = hierarchy (design §2 "weight creates hierarchy"): live work
49
+ * (active) LEADS in bold; terminal nodes (done/dead/canceled) recede dim; idle
50
+ * stays default weight (readable, not shouting). Mono-safe (weight, not hue).
51
+ * @param {string} status @returns {import('../../core/tui/draw.js').Style|undefined}
52
+ */
53
+ function nameStyle(status) {
54
+ if (status === 'active') return { bold: true };
55
+ if (status === 'done' || status === 'dead' || status === 'canceled') return { dim: true };
56
+ return undefined;
57
+ }
58
+
59
+ // ── Row → ListItemRow (left spans + right-flushed age) ─────────────────────────
60
+
61
+ /**
62
+ * Build one list row: a 1-cell left gutter (§2), the tree prefix (dim), the
63
+ * status glyph (hue), the name (weight = status), the dim `[kind/mode]` cue, and
64
+ * a bright-yellow `⚑N` attention flag when blocked — with the relative age
65
+ * RIGHT-FLUSHED into a clean scannable column via `ListItemRow.right`.
66
+ * @param {TreeRow} r @param {number} now
67
+ * @returns {import('../../core/tui/draw.js').ListItemRow}
68
+ */
69
+ function rowToItem(r, now) {
70
+ /** @type {import('../../core/tui/draw.js').Span[]} */
71
+ const spans = [{ text: ' ', style: undefined }]; // 1-cell gutter (rides the cursor bg)
72
+ if (r.prefix) spans.push({ text: r.prefix, style: { dim: true } });
73
+ spans.push({ text: r.glyph, style: glyphStyle(r.status) });
74
+ spans.push({ text: ' ', style: undefined });
75
+ spans.push({ text: r.name, style: nameStyle(r.status) });
76
+ spans.push({ text: ` [${r.kind}/${r.mode}]`, style: { fg: '90', dim: true } }); // muted: grey + dim (mono-safe)
77
+ if (r.blocked) spans.push({ text: ` ⚑${r.askCount}`, style: { fg: '93', bold: true } }); // attention
78
+
79
+ const age = relAge(r.created, now);
80
+ if (age) {
81
+ return { spans, right: [{ text: age, style: { fg: '90', dim: true } }] };
82
+ }
83
+ return { spans };
84
+ }
85
+
86
+ // ── render ─────────────────────────────────────────────────────────────────────
87
+
88
+ /**
89
+ * Paint the forest, or one of the four standard states. Pure (reads state,
90
+ * calls draw.*); the only state write is storing draw.list's adjusted scroll
91
+ * back, per the Draw contract.
92
+ * @param {CanvasState} state
93
+ * @param {import('../../core/tui/draw.js').Draw} draw
94
+ * @param {import('../../core/tui/draw.js').Rect} content
95
+ */
96
+ export function render(state, draw, content) {
97
+ if (content.width <= 0 || content.height <= 0) return;
98
+
99
+ if (state.rows.length === 0) {
100
+ // Hard not-ready: the data source is down and there is nothing to keep — a
101
+ // guided takeover owns the whole content rect (design §4/§5). The copy comes
102
+ // from the typed SourceError's `display` VERBATIM (the contract display/kind
103
+ // split — we never branch on `kind`); only the glyph + hue are a presentation
104
+ // map off `display.level` (error → ⚠ red, action → ⊙ yellow).
105
+ if (state.sourceError) {
106
+ const d = state.sourceError.display;
107
+ const g = d.level === 'action' ? { glyph: '⊙', fg: '33' } : { glyph: '⚠', fg: '31' };
108
+ notReadyState(draw, content, {
109
+ glyph: g.glyph,
110
+ glyphFg: g.fg,
111
+ headline: d.headline,
112
+ explanation: d.explanation,
113
+ nextStep: d.nextStep,
114
+ });
115
+ return;
116
+ }
117
+ // First load in flight — a skeleton, not a blank screen.
118
+ if (state.lastFetch === 0) {
119
+ loadingState(draw, content, { rows: Math.min(5, content.height), label: 'Loading the canvas…' });
120
+ return;
121
+ }
122
+ // Loaded, nothing to render — the reward state, two flavors.
123
+ if (state.totalNodes === 0) {
124
+ emptyState(draw, content, {
125
+ headline: 'No nodes on the canvas',
126
+ secondary: ['Spawn one with `crtr node new`.', 'Press g to refresh.'],
127
+ });
128
+ } else {
129
+ emptyState(draw, content, {
130
+ headline: 'All caught up',
131
+ secondary: [`${state.totalNodes} node${state.totalNodes === 1 ? '' : 's'} finished — none active.`, 'Press g to refresh.'],
132
+ });
133
+ }
134
+ return;
135
+ }
136
+
137
+ // The forest. A 1-row section gap below the header (§2 rhythm) when there is
138
+ // room; full-width list so the cursor highlight + age column reach the edges.
139
+ const now = Date.now();
140
+ const gap = content.height > 4 ? 1 : 0;
141
+ const listRect = {
142
+ row: content.row + gap,
143
+ col: content.col,
144
+ width: content.width,
145
+ height: content.height - gap,
146
+ };
147
+ const items = state.rows.map((r) => rowToItem(r, now));
148
+ const res = draw.list(listRect, items, state.cursor, state.scroll);
149
+ state.scroll = res.scroll; // store adjusted scroll back (Draw.list contract)
150
+ }
151
+
152
+ // ── keymap ───────────────────────────────────────────────────────────────
153
+
154
+ /**
155
+ * Read-only navigation: j/k move the cursor, g refreshes, q quits. No async
156
+ * actions from input — this is a monitor, not a controller. Footer hints come
157
+ * from these bindings' `hint` fields (the single source of truth).
158
+ * @type {import('../../core/view/contract.js').KeyBinding<CanvasState>[]}
159
+ */
160
+ export const keymap = [
161
+ { keys: ['j', 'down'], intent: 'cursorDown', hint: { keys: 'j/k', label: 'move' } },
162
+ { keys: ['k', 'up'], intent: 'cursorUp' },
163
+ { keys: ['g'], intent: 'refresh', hint: { keys: 'g', label: 'refresh' } },
164
+ { keys: ['q'], intent: 'quit', hint: { keys: 'q', label: 'quit' } },
165
+ ];
@@ -0,0 +1,120 @@
1
+ // @ts-check
2
+ /**
3
+ * Canvas Dashboard — the WEB presenter for the `canvas` view (React + Tailwind).
4
+ * Browser-only: consumed solely by the web serve path (Vite owns JSX +
5
+ * Tailwind); NEVER Node-imported. The default export is a pure function of
6
+ * `state`; DOM events call `dispatch(intentName, payload?)`.
7
+ *
8
+ * Same logical model as the TUI presenter (`state.rows` + `state.cursor`) read
9
+ * from the SAME portable `core.mjs` — zero shared rendering code with `tui.mjs`
10
+ * (the contract's accepted hard fork: `draw.*` has no web analog). The ASCII
11
+ * forest becomes a DOM tree, but the branch-prefix art is preserved verbatim in
12
+ * a monospace column so the hierarchy reads identically. The outer chrome (title
13
+ * / status / banner / state chip) is rendered by `<ViewChrome>`, which wraps this
14
+ * component — so do NOT render it here.
15
+ *
16
+ * VISUAL LANGUAGE (the web analog of tui.mjs's NUMERIC-SGR maps): the status hue
17
+ * matches `canvas browse`'s palette (active=green, idle=amber, done=cyan,
18
+ * dead=red, canceled=slate); live work LEADS in bold, terminal nodes recede;
19
+ * the ⚑N attention flag is bright yellow.
20
+ *
21
+ * @module canvas/web
22
+ */
23
+
24
+ import { relAge } from './core.mjs';
25
+ import { Loading, Empty, ErrorState, NotReady } from '@crouton-kit/crouter/web';
26
+
27
+ /** @typedef {import('./core.mjs').CanvasState} CanvasState */
28
+ /** @typedef {import('./core.mjs').TreeRow} TreeRow */
29
+
30
+ // ── Status vocabulary (the web analog of tui.mjs's STATUS_FG / nameStyle) ──────
31
+
32
+ /** @type {Record<string,string>} */
33
+ const STATUS_CLS = {
34
+ active: 'text-green-600',
35
+ idle: 'text-amber-600',
36
+ done: 'text-cyan-700',
37
+ dead: 'text-red-600',
38
+ canceled: 'text-slate-400',
39
+ };
40
+
41
+ /** @param {string} status @returns {string} */
42
+ function nameCls(status) {
43
+ if (status === 'active') return 'font-bold';
44
+ if (status === 'done' || status === 'dead' || status === 'canceled') return 'text-slate-400';
45
+ return '';
46
+ }
47
+
48
+ // ── Tree rows (the web analog of tui.mjs's rowToItem) ──────────────────────────
49
+
50
+ /** @param {{ row: TreeRow, selected: boolean, onClick: () => void }} props */
51
+ function TreeRowItem({ row, selected, onClick }) {
52
+ const now = Date.now();
53
+ const age = relAge(row.created, now);
54
+ return (
55
+ <li
56
+ className={`flex items-baseline gap-1.5 rounded px-2 py-0.5 ${selected ? 'bg-slate-200' : ''}`}
57
+ onClick={onClick}
58
+ >
59
+ {row.prefix ? <span className="whitespace-pre text-slate-400">{row.prefix}</span> : null}
60
+ <span className={STATUS_CLS[row.status] || 'text-slate-400'}>{row.glyph}</span>
61
+ <span className={nameCls(row.status)}>{row.name}</span>
62
+ <span className="text-slate-400">[{row.kind}/{row.mode}]</span>
63
+ {row.blocked ? <span className="font-bold text-yellow-500">⚑{row.askCount}</span> : null}
64
+ {age ? <span className="ml-auto shrink-0 text-slate-400">{age}</span> : null}
65
+ </li>
66
+ );
67
+ }
68
+
69
+ // ── The view ───────────────────────────────────────────────────────────────────
70
+
71
+ /**
72
+ * @param {import('../../core/view/contract.js').ViewProps<CanvasState>} props
73
+ */
74
+ export default function Canvas({ state, dispatch }) {
75
+ // ── Whole-view takeovers (no forest to render). When the data source is down
76
+ // and there is nothing to keep, the copy comes from the typed SourceError's
77
+ // `display` VERBATIM (the contract display/kind split — we never branch on
78
+ // `kind`); only the four-state component is a presentation map off
79
+ // `display.level` so the hue matches the TUI (error → red ErrorState,
80
+ // action → amber NotReady). ──
81
+ if (state.rows.length === 0) {
82
+ if (state.sourceError) {
83
+ const d = state.sourceError.display;
84
+ const Takeover = d.level === 'error' ? ErrorState : NotReady;
85
+ return (
86
+ <Takeover
87
+ headline={d.headline}
88
+ explanation={d.explanation}
89
+ nextStep={d.nextStep}
90
+ onRetry={() => dispatch('refresh')}
91
+ />
92
+ );
93
+ }
94
+ if (state.lastFetch === 0) {
95
+ return <Loading label="Loading the canvas…" />;
96
+ }
97
+ if (state.totalNodes === 0) {
98
+ return <Empty label="No nodes on the canvas — spawn one with `crtr node new`." />;
99
+ }
100
+ return <Empty label={`All caught up — ${state.totalNodes} node${state.totalNodes === 1 ? '' : 's'} finished, none active.`} />;
101
+ }
102
+
103
+ return (
104
+ <div
105
+ className="font-mono text-sm outline-none"
106
+ tabIndex={0}
107
+ onKeyDown={(e) => {
108
+ if (e.key === 'j' || e.key === 'ArrowDown') { dispatch('cursorDown'); e.preventDefault(); }
109
+ else if (e.key === 'k' || e.key === 'ArrowUp') { dispatch('cursorUp'); e.preventDefault(); }
110
+ else if (e.key === 'g') { dispatch('refresh'); }
111
+ }}
112
+ >
113
+ <ul>
114
+ {state.rows.map((row, i) => (
115
+ <TreeRowItem key={row.nodeId || i} row={row} selected={i === state.cursor} onClick={() => dispatch('activate', { nodeId: row.nodeId })} />
116
+ ))}
117
+ </ul>
118
+ </div>
119
+ );
120
+ }