@north-light/crouter 0.3.170 → 0.3.172

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 (670) hide show
  1. package/dist/api/client.d.ts +37 -11
  2. package/dist/api/client.js +84 -15
  3. package/dist/api/dto/human.d.ts +53 -39
  4. package/dist/api/dto/human.js +2 -3
  5. package/dist/api/dto/inbox.d.ts +0 -1
  6. package/dist/api/dto/nodes.d.ts +12 -0
  7. package/dist/api/dto/review-comments.d.ts +137 -0
  8. package/dist/api/dto/review-comments.js +5 -0
  9. package/dist/api/dto/reviews.d.ts +109 -0
  10. package/dist/api/dto/reviews.js +5 -0
  11. package/dist/api/index.d.ts +2 -0
  12. package/dist/api/index.js +2 -0
  13. package/dist/api/routes.d.ts +17 -4
  14. package/dist/api/routes.js +21 -5
  15. package/dist/build-root.d.ts +1 -16
  16. package/dist/build-root.js +1 -25
  17. package/dist/builtin-memory/00-runtime-base.md +7 -5
  18. package/dist/builtin-memory/04-base-worker.md +1 -1
  19. package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
  20. package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
  21. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +1 -1
  22. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -1
  23. package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -1
  24. package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -1
  25. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -1
  26. package/dist/builtin-memory/05-kinds/review/00-base.md +1 -1
  27. package/dist/builtin-memory/05-kinds/review/companion/00-base.md +20 -0
  28. package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -7
  29. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -3
  30. package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -3
  31. package/dist/builtin-memory/design.md +2 -2
  32. package/dist/builtin-memory/insights/capture.md +50 -0
  33. package/dist/builtin-memory/insights/init.md +45 -0
  34. package/dist/builtin-memory/insights/listen.md +9 -0
  35. package/dist/builtin-memory/internal/agent-shaping.md +2 -2
  36. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  37. package/dist/builtin-memory/internal/plugins.md +12 -11
  38. package/dist/builtin-memory/internal/storage-tiers.md +2 -2
  39. package/dist/builtin-memory/{planning.md → plan/roadmap.md} +3 -3
  40. package/dist/builtin-memory/plan.md +19 -0
  41. package/dist/builtin-memory/spec/guide.md +38 -0
  42. package/dist/builtin-memory/spec/requirements.md +31 -0
  43. package/dist/builtin-memory/spec/roadmap.md +35 -0
  44. package/dist/builtin-memory/spec.md +10 -86
  45. package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +3 -4
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +49 -5
  47. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +56 -0
  48. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +920 -0
  49. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +221 -156
  50. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +4 -5
  51. package/dist/cli.js +2 -6
  52. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +7 -35
  53. package/dist/clients/attach/__tests__/attach-keybindings.test.js +32 -16
  54. package/dist/clients/attach/__tests__/context-message.test.js +142 -6
  55. package/dist/clients/attach/__tests__/crtr-output.test.js +29 -45
  56. package/dist/clients/attach/__tests__/diagram.test.js +1 -1
  57. package/dist/clients/attach/__tests__/file-review-focus.test.js +48 -0
  58. package/dist/clients/attach/__tests__/group-activity.test.js +266 -0
  59. package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +32 -0
  60. package/dist/clients/attach/__tests__/session-identity-refresh.test.js +32 -0
  61. package/dist/clients/attach/__tests__/titled-editor-preview.test.js +1 -2
  62. package/dist/clients/attach/chrome/header.d.ts +10 -0
  63. package/dist/clients/attach/chrome/header.js +30 -0
  64. package/dist/clients/attach/chrome/recap.d.ts +7 -0
  65. package/dist/clients/attach/chrome/recap.js +19 -0
  66. package/dist/clients/attach/chrome/status-line.d.ts +3 -0
  67. package/dist/clients/attach/chrome/status-line.js +5 -0
  68. package/dist/clients/attach/chrome/widgets.js +11 -21
  69. package/dist/clients/attach/command.js +11 -7
  70. package/dist/clients/attach/config.d.ts +4 -0
  71. package/dist/clients/attach/config.js +3 -0
  72. package/dist/clients/attach/input/controller.d.ts +19 -0
  73. package/dist/clients/attach/input/controller.js +62 -28
  74. package/dist/clients/attach/input/titled-editor.d.ts +0 -4
  75. package/dist/clients/attach/input/titled-editor.js +2 -10
  76. package/dist/clients/attach/overlays/file-review.d.ts +9 -5
  77. package/dist/clients/attach/overlays/file-review.js +9 -70
  78. package/dist/clients/attach/overlays/help.d.ts +33 -0
  79. package/dist/clients/attach/overlays/help.js +204 -0
  80. package/dist/clients/attach/render/activity-slot.d.ts +4 -0
  81. package/dist/clients/attach/render/activity-slot.js +13 -0
  82. package/dist/clients/attach/render/chat-view.d.ts +117 -12
  83. package/dist/clients/attach/render/chat-view.js +604 -135
  84. package/dist/clients/attach/render/context-message.d.ts +2 -1
  85. package/dist/clients/attach/render/context-message.js +17 -13
  86. package/dist/clients/attach/render/crtr-output.js +1 -3
  87. package/dist/clients/attach/render/diagram.js +2 -2
  88. package/dist/clients/attach/render/edit-diff.d.ts +4 -1
  89. package/dist/clients/attach/render/edit-diff.js +7 -11
  90. package/dist/clients/attach/render/group-activity.d.ts +32 -0
  91. package/dist/clients/attach/render/group-activity.js +206 -0
  92. package/dist/clients/attach/render/group-recap.d.ts +10 -0
  93. package/dist/clients/attach/render/group-recap.js +93 -0
  94. package/dist/clients/attach/render/html-markdown.d.ts +17 -0
  95. package/dist/clients/attach/render/html-markdown.js +228 -0
  96. package/dist/clients/attach/render/measured-container.d.ts +96 -0
  97. package/dist/clients/attach/render/measured-container.js +322 -0
  98. package/dist/clients/attach/render/scroll-animation.d.ts +8 -0
  99. package/dist/clients/attach/render/scroll-animation.js +80 -0
  100. package/dist/clients/attach/render/tool-calls.js +6 -6
  101. package/dist/clients/attach/render/transcript-copy.d.ts +9 -0
  102. package/dist/clients/attach/render/transcript-copy.js +81 -0
  103. package/dist/clients/attach/render/viewport.d.ts +29 -0
  104. package/dist/clients/attach/render/viewport.js +159 -0
  105. package/dist/clients/attach/session/bindings.d.ts +10 -7
  106. package/dist/clients/attach/session/bindings.js +23 -8
  107. package/dist/clients/attach/session/connection.js +4 -5
  108. package/dist/clients/attach/session/context.d.ts +6 -4
  109. package/dist/clients/attach/session/frame.d.ts +34 -0
  110. package/dist/clients/attach/session/frame.js +176 -0
  111. package/dist/clients/attach/session/frames.d.ts +4 -1
  112. package/dist/clients/attach/session/frames.js +14 -1
  113. package/dist/clients/attach/session/identity.js +4 -3
  114. package/dist/clients/attach/session/input-wiring.d.ts +14 -4
  115. package/dist/clients/attach/session/input-wiring.js +15 -13
  116. package/dist/clients/attach/session/invariant.d.ts +9 -0
  117. package/dist/clients/attach/session/invariant.js +15 -0
  118. package/dist/clients/attach/session/keys.d.ts +10 -2
  119. package/dist/clients/attach/session/keys.js +13 -5
  120. package/dist/clients/attach/session/layout.d.ts +10 -8
  121. package/dist/clients/attach/session/layout.js +33 -34
  122. package/dist/clients/attach/session/mouse.d.ts +18 -0
  123. package/dist/clients/attach/session/mouse.js +64 -0
  124. package/dist/clients/attach/session/pane-tag.d.ts +3 -0
  125. package/dist/clients/attach/session/pane-tag.js +51 -8
  126. package/dist/clients/attach/session/reconnect.d.ts +3 -0
  127. package/dist/clients/attach/session/reconnect.js +42 -5
  128. package/dist/clients/attach/session/surface-frame.d.ts +20 -0
  129. package/dist/clients/attach/session/surface-frame.js +73 -0
  130. package/dist/clients/attach/session/surface-host.d.ts +64 -0
  131. package/dist/clients/attach/session/surface-host.js +255 -0
  132. package/dist/clients/attach/session/whip.d.ts +17 -0
  133. package/dist/clients/attach/session/whip.js +334 -0
  134. package/dist/clients/attach/slash/dispatch.d.ts +13 -1
  135. package/dist/clients/attach/slash/dispatch.js +51 -29
  136. package/dist/clients/attach/viewer.js +907 -819
  137. package/dist/clients/conversation/conversation.d.ts +65 -0
  138. package/dist/clients/conversation/conversation.js +318 -0
  139. package/dist/clients/conversation/frames.d.ts +30 -0
  140. package/dist/clients/conversation/frames.js +52 -0
  141. package/dist/clients/conversation/region.d.ts +51 -0
  142. package/dist/clients/conversation/region.js +265 -0
  143. package/dist/clients/conversation/submit.d.ts +38 -0
  144. package/dist/clients/conversation/submit.js +51 -0
  145. package/dist/clients/inbox/__tests__/inbox-controller.test.js +247 -0
  146. package/dist/clients/inbox/__tests__/mount-panel.test.js +776 -0
  147. package/dist/clients/inbox/controller.d.ts +79 -0
  148. package/dist/clients/inbox/controller.js +448 -0
  149. package/dist/clients/inbox/deck-adapter.d.ts +29 -0
  150. package/dist/clients/inbox/deck-adapter.js +62 -0
  151. package/dist/clients/inbox/layout.d.ts +8 -0
  152. package/dist/clients/inbox/layout.js +9 -0
  153. package/dist/clients/inbox/resolve.d.ts +10 -0
  154. package/dist/clients/inbox/resolve.js +34 -0
  155. package/dist/clients/inbox/review/__tests__/editor-roundtrip.test.js +29 -0
  156. package/dist/clients/inbox/review/__tests__/remap.test.js +196 -0
  157. package/dist/clients/inbox/review/__tests__/review-core.test.js +341 -0
  158. package/dist/clients/inbox/review/anchors.d.ts +41 -0
  159. package/dist/clients/inbox/review/anchors.js +89 -0
  160. package/dist/clients/inbox/review/columns.d.ts +22 -0
  161. package/dist/clients/inbox/review/columns.js +40 -0
  162. package/dist/clients/inbox/review/comments-client.d.ts +66 -0
  163. package/dist/clients/inbox/review/comments-client.js +98 -0
  164. package/dist/clients/inbox/review/composition.d.ts +60 -0
  165. package/dist/clients/inbox/review/composition.js +278 -0
  166. package/dist/clients/inbox/review/document-region.d.ts +120 -0
  167. package/dist/clients/inbox/review/document-region.js +902 -0
  168. package/dist/clients/inbox/review/frame.d.ts +45 -0
  169. package/dist/clients/inbox/review/frame.js +215 -0
  170. package/dist/clients/inbox/review/keys.d.ts +67 -0
  171. package/dist/clients/inbox/review/keys.js +130 -0
  172. package/dist/clients/inbox/review/launch.d.ts +10 -0
  173. package/dist/clients/inbox/review/launch.js +129 -0
  174. package/dist/clients/inbox/review/live-source.d.ts +24 -0
  175. package/dist/clients/inbox/review/live-source.js +160 -0
  176. package/dist/clients/inbox/review/nvim.d.ts +13 -0
  177. package/dist/clients/inbox/review/nvim.js +42 -0
  178. package/dist/clients/inbox/review/remap.d.ts +51 -0
  179. package/dist/clients/inbox/review/remap.js +157 -0
  180. package/dist/clients/inbox/review/review-client.d.ts +30 -0
  181. package/dist/clients/inbox/review/review-client.js +107 -0
  182. package/dist/clients/inbox/review/roundtrip.d.ts +5 -0
  183. package/dist/clients/inbox/review/roundtrip.js +36 -0
  184. package/dist/clients/inbox/review/state.d.ts +143 -0
  185. package/dist/clients/inbox/review/state.js +282 -0
  186. package/dist/clients/inbox/review-adapter.d.ts +29 -0
  187. package/dist/clients/inbox/review-adapter.js +92 -0
  188. package/dist/clients/inbox/review-visibility.d.ts +5 -0
  189. package/dist/clients/inbox/review-visibility.js +19 -0
  190. package/dist/clients/inbox/surface.d.ts +19 -0
  191. package/dist/clients/inbox/surface.js +128 -0
  192. package/dist/clients/inbox/tui/ansi.d.ts +66 -0
  193. package/dist/clients/inbox/tui/ansi.js +317 -0
  194. package/dist/clients/inbox/tui/clipboard.d.ts +2 -0
  195. package/dist/clients/inbox/tui/clipboard.js +26 -0
  196. package/dist/clients/inbox/tui/input.d.ts +7 -0
  197. package/dist/clients/inbox/tui/input.js +653 -0
  198. package/dist/clients/inbox/tui/keys.d.ts +28 -0
  199. package/dist/clients/inbox/tui/keys.js +111 -0
  200. package/dist/clients/inbox/tui/panel.d.ts +2 -0
  201. package/dist/clients/inbox/tui/panel.js +217 -0
  202. package/dist/clients/inbox/tui/render.d.ts +37 -0
  203. package/dist/clients/inbox/tui/render.js +476 -0
  204. package/dist/clients/inbox/tui/types.d.ts +57 -0
  205. package/dist/clients/inbox/tui/types.js +1 -0
  206. package/dist/clients/inbox/tui.d.ts +6 -0
  207. package/dist/clients/inbox/tui.js +74 -0
  208. package/dist/clients/surfaces/host.d.ts +66 -0
  209. package/dist/clients/surfaces/host.js +1 -0
  210. package/dist/clients/surfaces/region.d.ts +16 -0
  211. package/dist/clients/surfaces/region.js +1 -0
  212. package/dist/clients/web/__tests__/push-engine.test.js +14 -158
  213. package/dist/clients/web/dev-server.d.ts +3 -3
  214. package/dist/clients/web/dev-server.js +9 -23
  215. package/dist/clients/web/events.js +4 -6
  216. package/dist/clients/web/push-engine.d.ts +2 -66
  217. package/dist/clients/web/push-engine.js +30 -161
  218. package/dist/clients/web/push-registry.d.ts +0 -4
  219. package/dist/clients/web/push-registry.js +2 -7
  220. package/dist/clients/web/server.js +3 -35
  221. package/dist/clients/web/web-client/shared/protocol.d.ts +0 -108
  222. package/dist/clients/web/web-cmd.js +2 -2
  223. package/dist/commands/__tests__/human.test.js +27 -15
  224. package/dist/commands/api-client.js +3 -3
  225. package/dist/commands/canvas-browse.js +1 -1
  226. package/dist/commands/canvas-issue.js +1 -1
  227. package/dist/commands/canvas-use.js +1 -1
  228. package/dist/commands/human/doc.d.ts +2 -0
  229. package/dist/commands/human/doc.js +98 -0
  230. package/dist/commands/human/inbox.d.ts +2 -0
  231. package/dist/commands/human/inbox.js +101 -0
  232. package/dist/commands/human/prompts.d.ts +2 -3
  233. package/dist/commands/human/prompts.js +27 -180
  234. package/dist/commands/human/queue.d.ts +1 -5
  235. package/dist/commands/human/queue.js +54 -216
  236. package/dist/commands/human/review.d.ts +2 -0
  237. package/dist/commands/human/review.js +298 -0
  238. package/dist/commands/human/shared.d.ts +2 -69
  239. package/dist/commands/human/shared.js +1 -181
  240. package/dist/commands/human.js +15 -20
  241. package/dist/commands/memory/__tests__/lint.test.d.ts +1 -0
  242. package/dist/commands/memory/__tests__/lint.test.js +15 -0
  243. package/dist/commands/memory/delete.js +2 -2
  244. package/dist/commands/memory/lint.d.ts +1 -0
  245. package/dist/commands/memory/lint.js +21 -3
  246. package/dist/commands/memory/read.js +4 -4
  247. package/dist/commands/node.js +8 -7
  248. package/dist/commands/pkg/plugin-manage.js +143 -68
  249. package/dist/commands/surface-inspect.js +2 -2
  250. package/dist/commands/surface.js +6 -12
  251. package/dist/commands/sys/__tests__/setup-core.test.js +9 -5
  252. package/dist/commands/sys/__tests__/setup-front-door.test.js +7 -42
  253. package/dist/commands/sys/config.js +29 -3
  254. package/dist/commands/sys/feedback.js +1 -1
  255. package/dist/commands/sys/setup-core.d.ts +12 -11
  256. package/dist/commands/sys/setup-core.js +55 -46
  257. package/dist/commands/sys/setup-wizard.d.ts +4 -1
  258. package/dist/commands/sys/setup-wizard.js +50 -9
  259. package/dist/commands/sys/sync-deps.js +1 -1
  260. package/dist/commands/sys.js +4 -6
  261. package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -1
  262. package/dist/core/__tests__/broker-snapshot-history.test.js +9 -1
  263. package/dist/core/__tests__/dead-node-policy-table.test.js +3 -4
  264. package/dist/core/__tests__/fixtures/fake-engine.d.ts +8 -5
  265. package/dist/core/__tests__/fixtures/fake-engine.js +28 -2
  266. package/dist/core/__tests__/full/broker-provider-retry.test.js +87 -2
  267. package/dist/core/__tests__/full/broker-whip-interrupt.test.d.ts +1 -0
  268. package/dist/core/__tests__/full/broker-whip-interrupt.test.js +39 -0
  269. package/dist/core/__tests__/full/detach-focus.test.js +1 -1
  270. package/dist/core/__tests__/human-deliver-e2e.test.js +64 -64
  271. package/dist/core/__tests__/human-deliver.test.js +71 -345
  272. package/dist/core/__tests__/inline-memory-refs.test.js +2 -12
  273. package/dist/core/__tests__/memory-resolver-precedence.test.js +12 -15
  274. package/dist/core/__tests__/migration.test.js +10 -0
  275. package/dist/core/__tests__/model-pin-durability.test.js +14 -0
  276. package/dist/core/__tests__/phase4-review-migration.test.d.ts +1 -0
  277. package/dist/core/__tests__/phase4-review-migration.test.js +100 -0
  278. package/dist/core/__tests__/phase4-review-store.test.d.ts +1 -0
  279. package/dist/core/__tests__/phase4-review-store.test.js +143 -0
  280. package/dist/core/__tests__/remote-canvas-target.test.js +2 -2
  281. package/dist/core/__tests__/revive.test.js +22 -53
  282. package/dist/core/__tests__/session-cycles.test.js +48 -18
  283. package/dist/core/__tests__/spawn-no-kickoff.test.js +8 -12
  284. package/dist/core/__tests__/stop-guard.test.js +16 -1
  285. package/dist/core/__tests__/tmux-surface.test.js +21 -25
  286. package/dist/core/asset-root.d.ts +7 -0
  287. package/dist/core/asset-root.js +18 -0
  288. package/dist/core/broker-client/client.d.ts +0 -7
  289. package/dist/core/broker-client/client.js +4 -10
  290. package/dist/core/broker-client/transport-relay.d.ts +3 -4
  291. package/dist/core/broker-client/transport-relay.js +3 -4
  292. package/dist/core/canvas/__tests__/attention.test.js +1 -1
  293. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
  294. package/dist/core/canvas/__tests__/remote-transport.test.d.ts +1 -0
  295. package/dist/core/{view/__tests__/transport-remote.test.js → canvas/__tests__/remote-transport.test.js} +2 -2
  296. package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
  297. package/dist/core/canvas/attention.js +4 -4
  298. package/dist/core/canvas/canvas.d.ts +6 -11
  299. package/dist/core/canvas/canvas.js +11 -33
  300. package/dist/core/canvas/db.js +207 -38
  301. package/dist/core/canvas/extensions.d.ts +1 -1
  302. package/dist/core/canvas/extensions.js +8 -1
  303. package/dist/core/canvas/index.d.ts +0 -1
  304. package/dist/core/canvas/index.js +0 -1
  305. package/dist/core/canvas/nav-model.d.ts +1 -1
  306. package/dist/core/canvas/nav-model.js +1 -1
  307. package/dist/core/canvas/paths.d.ts +5 -0
  308. package/dist/core/canvas/paths.js +16 -0
  309. package/dist/core/canvas/remote-canvas-source.js +2 -2
  310. package/dist/core/canvas/remote-transport.d.ts +7 -0
  311. package/dist/core/{view/transport-remote.js → canvas/remote-transport.js} +3 -4
  312. package/dist/core/canvas/source.js +1 -1
  313. package/dist/core/canvas/status-glyph.js +4 -12
  314. package/dist/core/canvas/types.d.ts +10 -35
  315. package/dist/core/clipboard-text.d.ts +8 -0
  316. package/dist/core/clipboard-text.js +18 -0
  317. package/dist/core/command-manifests/registry.d.ts +1 -3
  318. package/dist/core/command-plugins/bundle.d.ts +29 -0
  319. package/dist/core/command-plugins/bundle.js +198 -0
  320. package/dist/core/command-plugins/discovery.d.ts +0 -8
  321. package/dist/core/command-plugins/discovery.js +2 -39
  322. package/dist/core/command-plugins/transport/http-fetch.d.ts +4 -30
  323. package/dist/core/command-plugins/transport/http-fetch.js +17 -95
  324. package/dist/core/command.d.ts +1 -13
  325. package/dist/core/command.js +1 -16
  326. package/dist/core/config.d.ts +4 -0
  327. package/dist/core/config.js +28 -3
  328. package/dist/core/document-lines.d.ts +4 -0
  329. package/dist/core/document-lines.js +6 -0
  330. package/dist/core/feed/feed.d.ts +2 -0
  331. package/dist/core/feed/feed.js +11 -7
  332. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +1 -0
  333. package/dist/core/human/__tests__/inbox-cancel-worker.js +7 -0
  334. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +1 -0
  335. package/dist/core/human/__tests__/inbox-claim-worker.js +17 -0
  336. package/dist/core/human/__tests__/inbox-core.test.d.ts +1 -0
  337. package/dist/core/human/__tests__/inbox-core.test.js +144 -0
  338. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +1 -0
  339. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +8 -0
  340. package/dist/core/human/__tests__/visible-paths.test.d.ts +1 -0
  341. package/dist/{clients/attach → core/human}/__tests__/visible-paths.test.js +9 -0
  342. package/dist/core/human/claim.d.ts +23 -0
  343. package/dist/core/human/claim.js +67 -0
  344. package/dist/core/human/convention.d.ts +30 -0
  345. package/dist/core/human/convention.js +202 -0
  346. package/dist/core/human/deck-factories.d.ts +8 -0
  347. package/dist/core/human/deck-factories.js +15 -0
  348. package/dist/core/human/deck-schema.d.ts +70 -0
  349. package/dist/core/human/deck-schema.js +92 -0
  350. package/dist/core/human/root.d.ts +7 -0
  351. package/dist/core/human/root.js +37 -0
  352. package/dist/core/human/scan.d.ts +3 -0
  353. package/dist/core/human/scan.js +76 -0
  354. package/dist/core/human/summary.d.ts +8 -0
  355. package/dist/core/human/summary.js +44 -0
  356. package/dist/core/human/tickets.d.ts +49 -0
  357. package/dist/core/human/tickets.js +190 -0
  358. package/dist/core/human/types.d.ts +136 -0
  359. package/dist/core/human/types.js +5 -0
  360. package/dist/{clients/attach → core/human}/visible-paths.d.ts +1 -1
  361. package/dist/{clients/attach → core/human}/visible-paths.js +3 -2
  362. package/dist/core/inspector/chrome.d.ts +6 -0
  363. package/dist/core/inspector/chrome.js +14 -0
  364. package/dist/core/inspector/contract.d.ts +105 -0
  365. package/dist/core/inspector/contract.js +1 -0
  366. package/dist/core/inspector/core.d.ts +4 -5
  367. package/dist/core/inspector/core.js +3 -5
  368. package/dist/core/inspector/host.d.ts +46 -0
  369. package/dist/core/{tui → inspector}/host.js +42 -208
  370. package/dist/core/inspector/text.d.ts +2 -2
  371. package/dist/core/inspector/transport.d.ts +6 -0
  372. package/dist/core/inspector/transport.js +36 -0
  373. package/dist/core/inspector/tui.d.ts +2 -2
  374. package/dist/core/inspector/tui.js +15 -15
  375. package/dist/core/keybindings/__tests__/inbox-affordance.test.js +11 -11
  376. package/dist/core/keybindings/__tests__/resolve.test.js +10 -19
  377. package/dist/core/keybindings/attach-control.d.ts +9 -3
  378. package/dist/core/keybindings/attach-control.js +3 -1
  379. package/dist/core/keybindings/catalog.d.ts +6 -5
  380. package/dist/core/keybindings/catalog.js +61 -133
  381. package/dist/core/keybindings/inbox.d.ts +5 -6
  382. package/dist/core/keybindings/inbox.js +9 -10
  383. package/dist/core/keybindings/index.d.ts +3 -3
  384. package/dist/core/keybindings/index.js +3 -3
  385. package/dist/core/keybindings/persistence.d.ts +5 -1
  386. package/dist/core/keybindings/persistence.js +24 -6
  387. package/dist/core/keybindings/resolve.d.ts +6 -0
  388. package/dist/core/keybindings/resolve.js +10 -3
  389. package/dist/core/memory/inline-ref-grammar.js +2 -3
  390. package/dist/core/memory-resolver.d.ts +27 -29
  391. package/dist/core/memory-resolver.js +45 -39
  392. package/dist/core/model-routes.d.ts +33 -0
  393. package/dist/core/model-routes.js +42 -3
  394. package/dist/core/preview-registry.js +17 -55
  395. package/dist/core/profiles/select.js +3 -3
  396. package/dist/core/{view/remote-canvas-target.d.ts → remote-canvas-target.d.ts} +2 -2
  397. package/dist/core/{view/remote-canvas-target.js → remote-canvas-target.js} +4 -4
  398. package/dist/core/review/__tests__/capture-origin.test.d.ts +1 -0
  399. package/dist/core/review/__tests__/capture-origin.test.js +139 -0
  400. package/dist/core/review/__tests__/comments.test.d.ts +1 -0
  401. package/dist/core/review/__tests__/comments.test.js +98 -0
  402. package/dist/core/review/__tests__/project.test.d.ts +1 -0
  403. package/dist/core/review/__tests__/project.test.js +71 -0
  404. package/dist/core/review/__tests__/remap.test.d.ts +1 -0
  405. package/dist/core/review/__tests__/remap.test.js +159 -0
  406. package/dist/core/review/__tests__/stage-identity.test.d.ts +1 -0
  407. package/dist/core/review/__tests__/stage-identity.test.js +140 -0
  408. package/dist/core/review/birth.d.ts +7 -0
  409. package/dist/core/review/birth.js +23 -0
  410. package/dist/core/review/comments.d.ts +69 -0
  411. package/dist/core/review/comments.js +295 -0
  412. package/dist/core/review/companion.d.ts +35 -0
  413. package/dist/core/review/companion.js +205 -0
  414. package/dist/core/review/document.d.ts +27 -0
  415. package/dist/core/review/document.js +138 -0
  416. package/dist/core/review/project.d.ts +13 -0
  417. package/dist/core/review/project.js +58 -0
  418. package/dist/core/review/realize.d.ts +19 -0
  419. package/dist/core/review/realize.js +217 -0
  420. package/dist/core/review/remap.d.ts +24 -0
  421. package/dist/core/review/remap.js +156 -0
  422. package/dist/core/review/signal.d.ts +5 -0
  423. package/dist/core/review/signal.js +31 -0
  424. package/dist/core/review/stage.d.ts +26 -0
  425. package/dist/core/review/stage.js +184 -0
  426. package/dist/core/review/store.d.ts +46 -0
  427. package/dist/core/review/store.js +163 -0
  428. package/dist/core/review/ticket-filter.d.ts +17 -0
  429. package/dist/core/review/ticket-filter.js +32 -0
  430. package/dist/core/review/types.d.ts +130 -0
  431. package/dist/core/review/types.js +23 -0
  432. package/dist/core/runtime/__tests__/session-visibility.test.d.ts +1 -0
  433. package/dist/core/runtime/__tests__/session-visibility.test.js +119 -0
  434. package/dist/core/runtime/bearings.d.ts +5 -17
  435. package/dist/core/runtime/bearings.js +88 -71
  436. package/dist/core/runtime/broker-protocol.d.ts +31 -8
  437. package/dist/core/runtime/broker.d.ts +15 -1
  438. package/dist/core/runtime/broker.js +573 -141
  439. package/dist/core/runtime/canvas-extensions.d.ts +4 -5
  440. package/dist/core/runtime/canvas-extensions.js +5 -5
  441. package/dist/core/runtime/front-door.js +4 -4
  442. package/dist/core/runtime/headless-pi.d.ts +24 -0
  443. package/dist/core/runtime/headless-pi.js +152 -0
  444. package/dist/core/runtime/kickoff.d.ts +1 -5
  445. package/dist/core/runtime/kickoff.js +1 -5
  446. package/dist/core/runtime/model-registry.d.ts +3 -0
  447. package/dist/core/runtime/model-registry.js +13 -0
  448. package/dist/core/runtime/naming-persist.d.ts +4 -0
  449. package/dist/core/runtime/naming-persist.js +27 -1
  450. package/dist/core/runtime/naming.d.ts +17 -12
  451. package/dist/core/runtime/naming.js +91 -140
  452. package/dist/core/runtime/node-read.js +19 -10
  453. package/dist/core/runtime/nodes.d.ts +9 -14
  454. package/dist/core/runtime/nodes.js +3 -53
  455. package/dist/core/runtime/package-health.d.ts +6 -21
  456. package/dist/core/runtime/package-health.js +12 -123
  457. package/dist/core/runtime/placement-tmux.d.ts +2 -1
  458. package/dist/core/runtime/placement-tmux.js +6 -4
  459. package/dist/core/runtime/placement.d.ts +1 -0
  460. package/dist/core/runtime/placement.js +4 -8
  461. package/dist/core/runtime/promote.js +3 -0
  462. package/dist/core/runtime/recap.d.ts +2 -7
  463. package/dist/core/runtime/recap.js +35 -69
  464. package/dist/core/runtime/revive.js +34 -77
  465. package/dist/core/runtime/session-cycles.d.ts +4 -0
  466. package/dist/core/runtime/session-cycles.js +14 -1
  467. package/dist/core/runtime/session-visibility.d.ts +37 -0
  468. package/dist/core/runtime/session-visibility.js +83 -0
  469. package/dist/core/runtime/spawn.js +10 -22
  470. package/dist/core/runtime/stop-guard.d.ts +1 -1
  471. package/dist/core/runtime/stop-guard.js +18 -13
  472. package/dist/core/runtime/surface-bg.js +1 -1
  473. package/dist/core/runtime/tmux-chrome.d.ts +1 -1
  474. package/dist/core/runtime/tmux-chrome.js +1 -1
  475. package/dist/core/runtime/tmux.d.ts +35 -7
  476. package/dist/core/runtime/tmux.js +439 -62
  477. package/dist/core/runtime/tool-group-summary.d.ts +19 -0
  478. package/dist/core/runtime/tool-group-summary.js +88 -0
  479. package/dist/core/scope.d.ts +2 -7
  480. package/dist/core/scope.js +9 -35
  481. package/dist/core/substrate/schema.d.ts +2 -2
  482. package/dist/core/termrender/code-doc.d.ts +12 -0
  483. package/dist/core/termrender/code-doc.js +92 -0
  484. package/dist/core/termrender/display.d.ts +12 -0
  485. package/dist/core/termrender/display.js +19 -0
  486. package/dist/core/termrender/termrender.d.ts +73 -0
  487. package/dist/core/termrender/termrender.js +795 -0
  488. package/dist/core/termrender/version.d.ts +1 -0
  489. package/dist/core/termrender/version.js +1 -0
  490. package/dist/core/tui/terminal.js +1 -2
  491. package/dist/core/user-settings.d.ts +71 -3
  492. package/dist/core/user-settings.js +83 -1
  493. package/dist/daemon/api/__tests__/inbox.test.js +44 -133
  494. package/dist/daemon/api/handlers/human.d.ts +0 -10
  495. package/dist/daemon/api/handlers/human.js +104 -702
  496. package/dist/daemon/api/handlers/inbox.js +113 -142
  497. package/dist/daemon/api/handlers/review-comments.d.ts +2 -0
  498. package/dist/daemon/api/handlers/review-comments.js +500 -0
  499. package/dist/daemon/api/handlers/reviews.d.ts +2 -0
  500. package/dist/daemon/api/handlers/reviews.js +287 -0
  501. package/dist/daemon/api/map.d.ts +22 -7
  502. package/dist/daemon/api/map.js +159 -11
  503. package/dist/daemon/api/server.js +4 -0
  504. package/dist/daemon/cron-run.js +6 -9
  505. package/dist/daemon/crtrd.js +17 -33
  506. package/dist/daemon/fleet.d.ts +1 -8
  507. package/dist/daemon/fleet.js +4 -30
  508. package/dist/daemon/human/finish.d.ts +14 -0
  509. package/dist/daemon/human/finish.js +115 -0
  510. package/dist/daemon/human/sweep.d.ts +6 -0
  511. package/dist/daemon/human/sweep.js +49 -0
  512. package/dist/daemon/messaging/node-message.d.ts +18 -0
  513. package/dist/daemon/messaging/node-message.js +70 -0
  514. package/dist/daemon/review/comment-notify.d.ts +26 -0
  515. package/dist/daemon/review/comment-notify.js +107 -0
  516. package/dist/daemon/review/deliver.d.ts +7 -0
  517. package/dist/daemon/review/deliver.js +56 -0
  518. package/dist/daemon/review/finish.d.ts +22 -0
  519. package/dist/daemon/review/finish.js +254 -0
  520. package/dist/daemon/review/sweep.d.ts +11 -0
  521. package/dist/daemon/review/sweep.js +120 -0
  522. package/dist/index.d.ts +2 -0
  523. package/dist/index.js +2 -2
  524. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +42 -64
  525. package/dist/pi-extensions/__tests__/canvas-recap.test.d.ts +1 -0
  526. package/dist/pi-extensions/__tests__/canvas-recap.test.js +159 -0
  527. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +16 -38
  528. package/dist/pi-extensions/__tests__/canvas-structured-output.test.d.ts +1 -0
  529. package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +63 -0
  530. package/dist/pi-extensions/canvas-context-intro.d.ts +8 -11
  531. package/dist/pi-extensions/canvas-context-intro.js +50 -104
  532. package/dist/pi-extensions/canvas-recap.d.ts +15 -2
  533. package/dist/pi-extensions/canvas-recap.js +192 -69
  534. package/dist/pi-extensions/canvas-review-boundary.d.ts +59 -0
  535. package/dist/pi-extensions/canvas-review-boundary.js +81 -0
  536. package/dist/pi-extensions/canvas-stophook.d.ts +3 -3
  537. package/dist/pi-extensions/canvas-stophook.js +78 -128
  538. package/dist/pi-extensions/canvas-structured-output.js +52 -8
  539. package/dist/shared/generated-context.d.ts +29 -4
  540. package/dist/shared/generated-context.js +122 -7
  541. package/dist/shared/tool-groups.d.ts +23 -0
  542. package/dist/shared/tool-groups.js +60 -0
  543. package/dist/shared/working-activity.d.ts +8 -0
  544. package/dist/shared/working-activity.js +26 -0
  545. package/dist/types.d.ts +36 -2
  546. package/dist/types.js +51 -0
  547. package/dist/web-client/assets/index-CCPaLeW7.css +2 -0
  548. package/dist/web-client/assets/index-kyOWsnZK.js +86 -0
  549. package/dist/web-client/index.html +2 -2
  550. package/dist/web-client/sw.js +1 -1
  551. package/docs/compat/hearth-crtr-v4.md +2 -2
  552. package/docs/compat/hearth-crtr-v5.md +4 -2
  553. package/docs/public-api.md +3 -3
  554. package/package.json +21 -14
  555. package/runtime.lock.json +4661 -1453
  556. package/scripts/postinstall.mjs +15 -2
  557. package/dist/builtin-pi-packages/pi-mode-switch/README.md +0 -36
  558. package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +0 -36
  559. package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +0 -449
  560. package/dist/builtin-pi-packages/pi-mode-switch/package.json +0 -14
  561. package/dist/builtin-pi-packages/pi-mode-switch/tsconfig.json +0 -9
  562. package/dist/builtin-views/_lib/states.mjs +0 -161
  563. package/dist/builtin-views/canvas/core.mjs +0 -657
  564. package/dist/builtin-views/canvas/text.mjs +0 -58
  565. package/dist/builtin-views/canvas/tui.mjs +0 -168
  566. package/dist/builtin-views/canvas/web.jsx +0 -121
  567. package/dist/builtin-views/chat/core.mjs +0 -684
  568. package/dist/builtin-views/chat/text.mjs +0 -101
  569. package/dist/builtin-views/chat/tui.mjs +0 -360
  570. package/dist/builtin-views/chat/web.jsx +0 -362
  571. package/dist/builtin-views/git-pr/core.mjs +0 -673
  572. package/dist/builtin-views/git-pr/text.mjs +0 -84
  573. package/dist/builtin-views/git-pr/tui.mjs +0 -301
  574. package/dist/builtin-views/git-pr/web.jsx +0 -216
  575. package/dist/builtin-views/inbox/_lib/render.mjs +0 -175
  576. package/dist/builtin-views/inbox/core.mjs +0 -1273
  577. package/dist/builtin-views/inbox/text.mjs +0 -73
  578. package/dist/builtin-views/inbox/tui.mjs +0 -314
  579. package/dist/builtin-views/inbox/web.jsx +0 -188
  580. package/dist/builtin-views/linkedin/core.mjs +0 -906
  581. package/dist/builtin-views/linkedin/text.mjs +0 -69
  582. package/dist/builtin-views/linkedin/tui.mjs +0 -413
  583. package/dist/builtin-views/linkedin/web.jsx +0 -206
  584. package/dist/builtin-views/prompt-review/core.mjs +0 -735
  585. package/dist/builtin-views/prompt-review/text.mjs +0 -15
  586. package/dist/builtin-views/prompt-review/tui.mjs +0 -196
  587. package/dist/builtin-views/prompt-review/web.jsx +0 -484
  588. package/dist/builtin-views/workspace-sidebar/__tests__/core.test.js +0 -50
  589. package/dist/builtin-views/workspace-sidebar/__tests__/core.test.ts +0 -53
  590. package/dist/builtin-views/workspace-sidebar/core.mjs +0 -670
  591. package/dist/builtin-views/workspace-sidebar/text.mjs +0 -53
  592. package/dist/builtin-views/workspace-sidebar/tui.mjs +0 -141
  593. package/dist/builtin-views/workspace-sidebar/web.jsx +0 -109
  594. package/dist/clients/attach/session/mode.d.ts +0 -25
  595. package/dist/clients/attach/session/mode.js +0 -97
  596. package/dist/commands/sys/promptstudio.d.ts +0 -2
  597. package/dist/commands/sys/promptstudio.js +0 -65
  598. package/dist/commands/view-cycle.d.ts +0 -2
  599. package/dist/commands/view-cycle.js +0 -130
  600. package/dist/commands/view-list.d.ts +0 -2
  601. package/dist/commands/view-list.js +0 -66
  602. package/dist/commands/view-new.d.ts +0 -2
  603. package/dist/commands/view-new.js +0 -74
  604. package/dist/commands/view-pick.d.ts +0 -6
  605. package/dist/commands/view-pick.js +0 -129
  606. package/dist/commands/view-run.d.ts +0 -2
  607. package/dist/commands/view-run.js +0 -214
  608. package/dist/commands/view.d.ts +0 -2
  609. package/dist/commands/view.js +0 -31
  610. package/dist/commands/workspace.d.ts +0 -2
  611. package/dist/commands/workspace.js +0 -165
  612. package/dist/core/__tests__/chat-view-reconnect.test.js +0 -105
  613. package/dist/core/__tests__/full/consult-startup-failure.test.js +0 -124
  614. package/dist/core/canvas/__tests__/human-work-outbox.test.js +0 -123
  615. package/dist/core/canvas/human-work-outbox.d.ts +0 -73
  616. package/dist/core/canvas/human-work-outbox.js +0 -261
  617. package/dist/core/command-plugins/store.d.ts +0 -16
  618. package/dist/core/command-plugins/store.js +0 -64
  619. package/dist/core/keybindings/__tests__/bespoke-consumers.test.js +0 -40
  620. package/dist/core/runtime/fault-recovery-nudge.d.ts +0 -3
  621. package/dist/core/runtime/fault-recovery-nudge.js +0 -3
  622. package/dist/core/tui/__tests__/host-keybindings.test.js +0 -113
  623. package/dist/core/tui/host.d.ts +0 -66
  624. package/dist/core/view/__tests__/transport-cache.test.js +0 -62
  625. package/dist/core/view/bridge.d.ts +0 -10
  626. package/dist/core/view/bridge.js +0 -31
  627. package/dist/core/view/chrome.d.ts +0 -9
  628. package/dist/core/view/chrome.js +0 -22
  629. package/dist/core/view/contract.d.ts +0 -205
  630. package/dist/core/view/contract.js +0 -23
  631. package/dist/core/view/loader.d.ts +0 -31
  632. package/dist/core/view/loader.js +0 -188
  633. package/dist/core/view/stream-local.d.ts +0 -3
  634. package/dist/core/view/stream-local.js +0 -231
  635. package/dist/core/view/transport-cache.d.ts +0 -8
  636. package/dist/core/view/transport-cache.js +0 -38
  637. package/dist/core/view/transport-local.d.ts +0 -7
  638. package/dist/core/view/transport-local.js +0 -83
  639. package/dist/core/view/transport-remote.d.ts +0 -2
  640. package/dist/core/view/transport.d.ts +0 -10
  641. package/dist/core/view/transport.js +0 -15
  642. package/dist/pi-extensions/naming-tool.d.ts +0 -24
  643. package/dist/pi-extensions/naming-tool.js +0 -67
  644. package/dist/prompts/view.d.ts +0 -7
  645. package/dist/prompts/view.js +0 -172
  646. package/dist/web/ViewChrome.d.ts +0 -7
  647. package/dist/web/ViewChrome.js +0 -28
  648. package/dist/web/ViewPane.d.ts +0 -39
  649. package/dist/web/ViewPane.js +0 -48
  650. package/dist/web/index.d.ts +0 -8
  651. package/dist/web/index.js +0 -22
  652. package/dist/web/runtime.d.ts +0 -39
  653. package/dist/web/runtime.js +0 -232
  654. package/dist/web/states.d.ts +0 -24
  655. package/dist/web/states.js +0 -24
  656. package/dist/web/transport-http.d.ts +0 -5
  657. package/dist/web/transport-http.js +0 -34
  658. package/dist/web/transport-stream.d.ts +0 -3
  659. package/dist/web/transport-stream.js +0 -204
  660. package/dist/web-client/assets/index-U_NZ66VE.js +0 -79
  661. package/dist/web-client/assets/index-aaeu4adv.css +0 -2
  662. /package/dist/{builtin-views/workspace-sidebar/__tests__/core.test.d.ts → clients/attach/__tests__/file-review-focus.test.d.ts} +0 -0
  663. /package/dist/clients/attach/__tests__/{visible-paths.test.d.ts → group-activity.test.d.ts} +0 -0
  664. /package/dist/{core/__tests__/chat-view-reconnect.test.d.ts → clients/attach/__tests__/input-controller-extension-command.test.d.ts} +0 -0
  665. /package/dist/{core/__tests__/full/consult-startup-failure.test.d.ts → clients/attach/__tests__/session-identity-refresh.test.d.ts} +0 -0
  666. /package/dist/{core/canvas/__tests__/human-work-outbox.test.d.ts → clients/inbox/__tests__/inbox-controller.test.d.ts} +0 -0
  667. /package/dist/{core/keybindings/__tests__/bespoke-consumers.test.d.ts → clients/inbox/__tests__/mount-panel.test.d.ts} +0 -0
  668. /package/dist/{core/tui/__tests__/host-keybindings.test.d.ts → clients/inbox/review/__tests__/editor-roundtrip.test.d.ts} +0 -0
  669. /package/dist/{core/view/__tests__/transport-cache.test.d.ts → clients/inbox/review/__tests__/remap.test.d.ts} +0 -0
  670. /package/dist/{core/view/__tests__/transport-remote.test.d.ts → clients/inbox/review/__tests__/review-core.test.d.ts} +0 -0
@@ -0,0 +1,15 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { lintShortPreviewBody } from '../lint.js';
4
+ const previewMemory = {
5
+ 'system-prompt-visibility': 'preview',
6
+ 'file-read-visibility': 'none',
7
+ };
8
+ test('memory lint warns when a preview body is short enough to inline', () => {
9
+ const shortBody = Array.from({ length: 29 }, (_, index) => `word${index}`).join(' ');
10
+ assert.match(lintShortPreviewBody(previewMemory, shortBody) ?? '', /body is 29 words but system-prompt-visibility is `preview`; use `content`/);
11
+ const contentMemory = { ...previewMemory, 'system-prompt-visibility': 'content' };
12
+ assert.equal(lintShortPreviewBody(contentMemory, shortBody), null);
13
+ const thresholdBody = Array.from({ length: 30 }, (_, index) => `word${index}`).join(' ');
14
+ assert.equal(lintShortPreviewBody(previewMemory, thresholdBody), null);
15
+ });
@@ -22,12 +22,12 @@ function pruneEmptyParents(filePath, nameSegments) {
22
22
  export const deleteLeaf = defineLeaf({
23
23
  name: 'delete',
24
24
  description: 'delete a memory document by name',
25
- whenToUse: 'a stored document is wrong, obsolete, or superseded and should be removed — the sanctioned way to delete one, so you never rm the markdown off disk. Resolves the name exactly as `read` does (node > project stack > profile > user precedence, leaf-name fallback) and removes that file: if you can read it, you can delete it. Refuses docs you do not own — builtin docs (shipped with the package) and installed-plugin docs (managed by `crtr pkg`) — and refuses an ambiguous leaf name rather than guessing which doc to destroy; pass the full `area/topic` name or `--scope` to pin one.',
25
+ whenToUse: 'a stored document is wrong, obsolete, or superseded and should be removed — the sanctioned way to delete one, so you never rm the markdown off disk. Resolves the name exactly as `read` does (exact/direct matches by node > project stack > profile > user precedence, then leaf-name fallback) and removes that file: if you can read it, you can delete it. Refuses docs you do not own — builtin docs (shipped with the package) and installed-plugin docs (managed by `crtr pkg`) — and refuses an ambiguous leaf name rather than guessing which doc to destroy; pass the full `area/topic` name or `--scope` to pin one.',
26
26
  help: {
27
27
  name: 'memory delete',
28
28
  summary: 'resolve a path-derived name and remove that document from its scope store',
29
29
  params: [
30
- { kind: 'positional', name: 'name', required: true, constraint: 'Path-derived memory identifier (e.g. `topic` or `area/topic`), resolved as `read` resolves it: precedence node > project stack > profile > user, with leaf-name fallback. A leaf that maps to genuinely different docs across scopes is rejected as ambiguous — pass the full name or --scope to disambiguate. May be scope-prefixed (`user/topic`) to pin the store directly.' },
30
+ { kind: 'positional', name: 'name', required: true, constraint: 'Path-derived memory identifier (e.g. `topic` or `area/topic`), resolved as `read` resolves it: exact identity/direct path by precedence node > project stack > profile > user, then bare leaf fallback. A leaf matching multiple different docs in one source is rejected as ambiguous — pass the full name or --scope to disambiguate. May be scope-prefixed (`user/topic`) to pin the store directly.' },
31
31
  { kind: 'flag', name: 'scope', type: 'enum', choices: [...MEMORY_SCOPES], required: false, constraint: 'Restrict resolution to this scope before deleting. Use it to disambiguate a leaf name present at multiple scopes, or to assert which store you mean. builtin is not a choice — builtin docs ship with the package and cannot be deleted.' },
32
32
  ],
33
33
  output: [
@@ -3,6 +3,7 @@
3
3
  * `docName` is the doc's canonical resolver identity (explicit frontmatter
4
4
  * `name`, else the normalized path-derived name) — persona layers under
5
5
  * `kinds/` are recognized by it and never capped. */
6
+ export declare function lintShortPreviewBody(fm: Record<string, unknown>, body: string): string | null;
6
7
  export declare function lintBodyLength(fm: Record<string, unknown>, body: string, docName: string): string | null;
7
8
  /** Schema checks for a doc living in a substrate memory dir: a memory store
8
9
  * holds ONLY substrate docs, so a missing/invalid `kind` is an authoring
@@ -44,6 +44,8 @@ const RUNG_FIELDS = ['system-prompt-visibility', 'file-read-visibility'];
44
44
  const SYSTEM_CONTENT_MAX_WORDS = 1000;
45
45
  const FILE_READ_MAX_WORDS = 1000;
46
46
  const SYSTEM_PREVIEW_MAX_WORDS = 3000;
47
+ /** A routing line costs more than it saves for a short rule or fact. */
48
+ const PREVIEW_TO_CONTENT_MAX_WORDS = 30;
47
49
  /** Rules a doc may suppress via frontmatter `lint-ignore`. */
48
50
  const SUPPRESSIBLE_RULES = ['length'];
49
51
  function ignoresRule(fm, rule) {
@@ -59,6 +61,19 @@ function countBodyWords(body) {
59
61
  * `docName` is the doc's canonical resolver identity (explicit frontmatter
60
62
  * `name`, else the normalized path-derived name) — persona layers under
61
63
  * `kinds/` are recognized by it and never capped. */
64
+ export function lintShortPreviewBody(fm, body) {
65
+ const words = countBodyWords(body);
66
+ if (words >= PREVIEW_TO_CONTENT_MAX_WORDS)
67
+ return null;
68
+ const previewAxes = [
69
+ fm['system-prompt-visibility'] === 'preview' ? 'system-prompt-visibility' : undefined,
70
+ fm['file-read-visibility'] === 'preview' ? 'file-read-visibility' : undefined,
71
+ ].filter((axis) => axis !== undefined);
72
+ if (previewAxes.length === 0)
73
+ return null;
74
+ const verb = previewAxes.length === 1 ? 'is' : 'are';
75
+ return `body is ${words} words but ${previewAxes.join(' and ')} ${verb} \`preview\`; use \`content\` on that axis so agents receive the whole rule without a separate memory read`;
76
+ }
62
77
  export function lintBodyLength(fm, body, docName) {
63
78
  if (ignoresRule(fm, 'length'))
64
79
  return null;
@@ -175,7 +190,7 @@ export function lintSubstrateSchema(fm) {
175
190
  * corpus. A dangling link is an authoring error caught HERE, never silently
176
191
  * carried; leaf-name fallback is deliberately excluded so links stay stable
177
192
  * as the graph grows and another document acquires the same leaf name. */
178
- function lintFile(file, substrateStore, findings, corpusNames, fallbackName) {
193
+ function lintFile(file, substrateStore, findings, warnings, corpusNames, fallbackName) {
179
194
  let fm;
180
195
  let body;
181
196
  try {
@@ -195,6 +210,9 @@ function lintFile(file, substrateStore, findings, corpusNames, fallbackName) {
195
210
  const lengthError = lintBodyLength(fm, body, resolveDocName(fm, fallbackName));
196
211
  if (lengthError !== null)
197
212
  findings.push({ path: file, error: lengthError });
213
+ const shortPreviewWarning = lintShortPreviewBody(fm, body);
214
+ if (shortPreviewWarning !== null)
215
+ warnings.push(`${file}: ${shortPreviewWarning}`);
198
216
  }
199
217
  for (const name of docLinkNames(body)) {
200
218
  if (!corpusNames.has(name)) {
@@ -252,7 +270,7 @@ export const lintLeaf = defineLeaf({
252
270
  continue;
253
271
  memoryCount += 1;
254
272
  const fallbackName = normalizeDocName(relPath.replace(/\.md$/, ''));
255
- lintFile(file, basename(file) !== 'MEMORY.md', findings, corpusNames, fallbackName);
273
+ lintFile(file, basename(file) !== 'MEMORY.md', findings, warnings, corpusNames, fallbackName);
256
274
  }
257
275
  };
258
276
  for (const root of projectScopeRoots()) {
@@ -353,7 +371,7 @@ export const lintLeaf = defineLeaf({
353
371
  corpora: { memory_stores: memoryCount, profile_projects: profileProjects },
354
372
  findings: [],
355
373
  warnings,
356
- follow_up: warnings.length > 0 ? 'Corpus green — resolve the warning above to give this directory a routed memory front door.' : 'Corpus green — zero invalid frontmatter docs.',
374
+ follow_up: warnings.length > 0 ? 'Corpus green — review the warnings above for non-fatal authoring improvements.' : 'Corpus green — zero invalid frontmatter docs.',
357
375
  };
358
376
  },
359
377
  });
@@ -10,12 +10,12 @@ import { MEMORY_KINDS } from './shared.js';
10
10
  export const readLeaf = defineLeaf({
11
11
  name: 'read',
12
12
  description: 'load a memory document body by name',
13
- whenToUse: 'a task in front of you matches a stored document and you already know its name — read it before improvising. Resolves the path-derived name across scopes by precedence (node > project stack > profile > user > builtin), with leaf-name fallback. You name the document by its crtr identifier, never a file path — do not cat or find the markdown off disk. Reach for `crtr memory find` first when you do not yet know which document applies.',
13
+ whenToUse: 'a task in front of you matches a stored document and you already know its name — read it before improvising. Exact identity and direct-path matches resolve by scope precedence (node > project stack > profile > user > builtin); bare leaf-name fallback is considered only when no such match exists. You name the document by its crtr identifier, never a file path — do not cat or find the markdown off disk. Reach for `crtr memory find` first when you do not yet know which document applies.',
14
14
  help: {
15
15
  name: 'memory read',
16
16
  summary: 'resolve a path-derived name to its document body, frontmatter stripped unless --frontmatter',
17
17
  params: [
18
- { kind: 'positional', name: 'name', required: true, constraint: 'Path-derived memory identifier (e.g. `topic` or `area/topic`). Resolved across scopes by precedence: node > project stack > profile > user > builtin, with leaf-name fallback.' },
18
+ { kind: 'positional', name: 'name', required: true, constraint: 'Path-derived memory identifier (e.g. `topic` or `area/topic`). Exact identity and direct-path matches resolve by scope precedence: node > project stack > profile > user > builtin. A bare leaf falls back only when no exact/direct match exists.' },
19
19
  { kind: 'flag', name: 'kind', type: 'enum', choices: [...MEMORY_KINDS], required: false, constraint: 'Narrows resolution when the name is ambiguous across kinds.' },
20
20
  { kind: 'flag', name: 'frontmatter', type: 'bool', required: false, constraint: 'When present, includes the YAML frontmatter in the returned body. Off by default — only the body is returned.' },
21
21
  ],
@@ -35,8 +35,8 @@ export const readLeaf = defineLeaf({
35
35
  const nameRaw = input['name'];
36
36
  const kindFilter = input['kind'];
37
37
  const includeFrontmatter = input['frontmatter'];
38
- // Resolve a substrate/memory document across scopes (node > project stack
39
- // > profile > user > builtin, with leaf-name fallback). --kind is threaded
38
+ // Resolve a substrate/memory document across scopes: exact/direct matches
39
+ // by precedence first, then leaf-name fallback. --kind is threaded
40
40
  // INTO resolution (not a post-filter): a nearer wrong-kind doc is skipped
41
41
  // so a farther matching-kind doc is found instead of shadowing it into a
42
42
  // false not_found. The substrate corpus now includes plugin docs (mounted
@@ -3,7 +3,7 @@
3
3
  // flow through `crtr push`, and scheduled commands live under `crtr cron`.
4
4
  import { defineLeaf, defineBranch } from '../core/command.js';
5
5
  import { InputError } from '../core/io.js';
6
- import { inboxPopupHint } from '../core/keybindings/index.js';
6
+ import { inboxHint } from '../core/keybindings/index.js';
7
7
  import { writeClipboardText } from '../core/clipboard-text.js';
8
8
  import { mark } from '../core/timing.js';
9
9
  import { displayMessage } from '../core/runtime/tmux-chrome.js';
@@ -737,7 +737,7 @@ export const surfaceNodeFocusLeaf = defineLeaf({
737
737
  throw new InputError({
738
738
  error: 'not_focusable',
739
739
  message: `node ${id} is a human-ask (kind:human), not a conversation — it has no pi session to focus.`,
740
- next: `The pending question is queued for the human (${inboxPopupHint()} opens the inbox popup); see it with \`crtr human list\`, or retract it with \`crtr human cancel ${id}\`.`,
740
+ next: `The pending question is queued for the human (${inboxHint()} opens the inbox); see it with \`crtr human list\`, or retract it with \`crtr human cancel ${id}\`.`,
741
741
  });
742
742
  }
743
743
  // Opening history is not resuming work. A terminal/canceled/crashed node has
@@ -1733,11 +1733,11 @@ const nodeSubscription = defineBranch({
1733
1733
  const nodePromote = defineLeaf({
1734
1734
  name: 'promote',
1735
1735
  description: 'become an orchestrator of a chosen kind',
1736
- whenToUse: 'what remains needs decomposition across delegated children — many phases to delegate and persist across refreshes — so become an orchestrator: a long-lived, roadmap-holding node that fans work out to children and survives context refreshes (`node yield`). Specialize it to the kind of work it now steers, and optionally make it interactable so it stays dormant between inbox/human pings instead of owing a final. Do NOT reach for this for work that fits one window, or merely because you spawned a child — a base worker that spawns a helper and ends with `push final` never needs to promote',
1736
+ whenToUse: 'the remaining work contains independent units that can run in parallel, and the task is large enough that coordinating and integrating them will materially improve intelligence, productivity, or elapsed throughput. Become a long-lived, roadmap-holding orchestrator whose primary job is steering those children across refreshes (`node yield`). Keep sequential or tightly coupled work in base mode even when it spans phases or context windows; spawning one helper does not itself require promotion',
1737
1737
  tier: 'important',
1738
1738
  help: {
1739
1739
  name: 'node promote',
1740
- summary: 'promote yourself to an orchestrator — do this when your task outgrows one context window (many phases to delegate and persist across refreshes); not for work that fits one window, and not merely because you spawned a child. Mode only — lifecycle stays as-is unless you pass --resident',
1740
+ summary: 'promote yourself to an orchestrator when worthwhile parallel delegation should make coordination your primary job; task duration, sequential phases, or one helper do not qualify. Mode only — lifecycle stays as-is unless you pass --resident',
1741
1741
  params: [
1742
1742
  { kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Specialize as this kind of orchestrator. The <kinds> list below names every top-level installable kind and when to use each; a sub-kind (e.g. plan/reviewers/security) is valid too by exact path but not listed here. For an exact composed persona list, use `crtr sys prompt-review --list --kind <kind>` with the target kind. Defaults to your current kind. Promoting from a generic kind? CHOOSE a concrete one — it sets the orchestrator persona you revive into.' },
1743
1743
  { kind: 'flag', name: 'resident', type: 'bool', required: false, constraint: 'ALSO flip lifecycle→resident: make the node interactable — it stays dormant, woken by inbox/human, and is never forced to submit a final. Omit to stay terminal/orchestrator (delegates + holds a roadmap, but still owes a final up the spine and reaps when done).' },
@@ -1882,14 +1882,14 @@ const nodeLifecycle = defineBranch({
1882
1882
  const nodeYield = defineLeaf({
1883
1883
  name: 'yield',
1884
1884
  description: 'refresh your context, same mode, against your roadmap or goal',
1885
- whenToUse: 'your context is filling but the mandate remains; refresh in the same mode, or combine the refresh with promotion when the remaining work now needs delegated phases',
1885
+ whenToUse: 'your context is filling but the mandate remains; refresh in the same mode, or combine the refresh with promotion when meaningful independent work can run in parallel and coordinating it should become your primary job',
1886
1886
  help: {
1887
1887
  name: 'node yield',
1888
1888
  summary: 'request a fresh context window against your roadmap or original goal; mode stays unchanged unless --promote is passed',
1889
1889
  guide: 'Persist anything needed after refresh and send any pending human question before invoking; in-flight asks survive the refresh.',
1890
1890
  params: [
1891
- { kind: 'flag', name: 'promote', type: 'bool', required: false, constraint: 'Also become an orchestrator as you refresh — the one-step form of yield + promote, for when what remains needs decomposition across delegated children. Omit for a plain, mode-preserving refresh (a base node stays base). Already an orchestrator? This is not an error: your mode stays orchestrator and a missing roadmap is seeded.' },
1892
- { kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Respecialize as you refresh — change your kind to this (developer, review, spec, design, plan, explore, general). Defaults to your current kind. Combines with either form: with --promote it sets the orchestrator kind you become; without it, it reshapes your CURRENT mode in place.' },
1891
+ { kind: 'flag', name: 'promote', type: 'bool', required: false, constraint: 'Also become an orchestrator as you refresh. Pass only when (1) the remaining work contains independent units that can run in parallel and (2) the task is large enough that parallel execution will materially improve intelligence, productivity, or elapsed throughput after coordination and synthesis. Task length, context exhaustion, sequential phases, or one helper are not enough; keep hands-on work in base mode and yield again as needed. Promote when coordinating and integrating children becomes your primary job. Already an orchestrator? This is not an error: your mode stays orchestrator and a missing roadmap is seeded.' },
1892
+ { kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Respecialize as you refresh. The <kinds> list below names every top-level available kind and when to choose it; a sub-kind (e.g. plan/reviewers/security) is valid too by exact path but not listed here. Defaults to your current kind. With --promote it sets the orchestrator kind you become; without --promote it changes the kind while preserving your current mode.' },
1893
1893
  { kind: 'flag', name: 'model', type: 'enum', choices: ['ultra', 'strong'], required: false, constraint: 'Change the model your fresh revive runs on, by capability tier: `ultra` (frontier — reserve for high-taste judgment or enormous work: speccing, planning something large, e2e-testing something hard to test) or `strong` (opus — regular dev work). Omit to keep your current model. A node steering work is never weaker than opus, so these are the only two choices; the change is durable across future revives.' },
1894
1894
  // Deliberate fail-first contract (#395): builtin orchestration guidance shows bare
1895
1895
  // `crtr node yield`; that invocation fails fast and surfaces yield's full help just in
@@ -1903,6 +1903,7 @@ const nodeYield = defineLeaf({
1903
1903
  { name: 'model', type: 'string', required: false, constraint: 'The model tier your fresh revive will run on, present only when you changed it with --model.' },
1904
1904
  { name: 'will_refresh', type: 'boolean', required: true, constraint: 'Always true: end your turn and you will revive fresh.' },
1905
1905
  ],
1906
+ dynamicState: () => kindsStateBlock(),
1906
1907
  outputKind: 'object',
1907
1908
  effects: ['Sets intent=refresh; the stophook shuts the process down on next stop and the daemon revives it fresh.', '--kind and/or --model durably reshape the node (kind respecialization, model-tier pin) before the refresh-revive; --promote additionally flips mode→orchestrator and seeds a roadmap scaffold — mode is otherwise left exactly as it was.'],
1908
1909
  },
@@ -1,19 +1,19 @@
1
- import { join, resolve, isAbsolute } from 'node:path';
2
- import { renameSync } from 'node:fs';
1
+ import { join, resolve, isAbsolute, sep } from 'node:path';
2
+ import { renameSync, writeFileSync } from 'node:fs';
3
+ import { createHash } from 'node:crypto';
3
4
  import { defineLeaf } from '../../core/command.js';
4
- import { CrtrError, notFound, usage, general, network } from '../../core/errors.js';
5
+ import { notFound, usage, general, network } from '../../core/errors.js';
5
6
  import { findMarketplaceByName, findPluginByName, listAllPlugins } from '../../core/resolver.js';
6
7
  import { pluginsDir, ensureProjectScopeRoot, userScopeRoot, resolveScopeArg, projectScopeRoot, requireScopeRoot, } from '../../core/scope.js';
7
8
  import { updateConfig, updateState, ensureScopeInitialized } from '../../core/config.js';
8
9
  import { pathExists, ensureDir, removePath, nowIso, linkOrCopy, isSymlink, atomicWriteJson } from '../../core/fs-utils.js';
9
10
  import { clone, pull, deriveNameFromUrl, currentSha, isGitRepo } from '../../core/git.js';
10
- import { pluginManifestPath, readMarketplaceManifest, readPluginManifest } from '../../core/manifest.js';
11
+ import { readMarketplaceManifest, readPluginManifest } from '../../core/manifest.js';
11
12
  import { validatePluginCommands, validateEffectiveCommandPlugins } from '../../core/command-plugins/discovery.js';
12
13
  import { normalizeEndpoint, validateEndpoint, validateHttpPluginTransport } from '../../core/command-plugins/endpoint.js';
13
- import { resolveHttpPluginManifestStore, writeHttpPluginManifest } from '../../core/command-plugins/store.js';
14
- import { fetchHttpPluginManifest, refreshHttpPlugin } from '../../core/command-plugins/transport/http-fetch.js';
14
+ import { validatePluginBundle } from '../../core/command-plugins/bundle.js';
15
+ import { fetchHttpPluginBundle } from '../../core/command-plugins/transport/http-fetch.js';
15
16
  import { SUBTREE_NAMES } from '../../build-root.js';
16
- import { ExitCode } from '../../types.js';
17
17
  import { isGitUrl, setPluginEnabled, resolveInstallScope } from './shared.js';
18
18
  /** Validate a just-installed/updated plugin's command manifest, if it declares
19
19
  * one. Returns undefined for plugins without a `commands` pointer. Never
@@ -32,66 +32,137 @@ function commandReport(name, scope) {
32
32
  return { mounts: v.contributions.map((c) => c.node.name), issues: v.issues };
33
33
  }
34
34
  const PLUGIN_NAME_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
35
- function unsafeHttpManifestPath(name, commands) {
36
- throw new CrtrError('command_path_unsafe', `HTTP plugin "${name}" commands pointer escapes the plugin root or is not a regular file`, ExitCode.USAGE, { received: commands, field: 'commands', next: 'Fix plugin.json.commands.' });
37
- }
38
35
  function validateHttpInstall(name, endpoint, authEnv) {
39
- if (typeof name !== 'string' || !PLUGIN_NAME_RE.test(name)) {
36
+ if (typeof name !== 'string' || !PLUGIN_NAME_RE.test(name))
40
37
  throw usage('invalid --name: expected a lowercase kebab-case plugin handle');
41
- }
42
38
  const endpointValidation = validateEndpoint(endpoint);
43
- if (!endpointValidation.isValid) {
39
+ if (!endpointValidation.isValid)
44
40
  throw usage(`invalid --endpoint: ${endpointValidation.errors.join('; ')}`);
45
- }
46
41
  const normalizedEndpoint = normalizeEndpoint(endpoint);
47
- const transportValidation = validateHttpPluginTransport({
48
- kind: 'http',
49
- endpoint: normalizedEndpoint,
50
- ...(authEnv !== undefined ? { authEnv } : {}),
51
- });
52
- if (transportValidation.transport === undefined) {
42
+ const transportValidation = validateHttpPluginTransport({ kind: 'http', endpoint: normalizedEndpoint, ...(authEnv !== undefined ? { authEnv } : {}) });
43
+ if (transportValidation.transport === undefined)
53
44
  throw usage(`invalid HTTP plugin transport: ${transportValidation.errors.join('; ')}`);
54
- }
55
45
  return transportValidation.transport;
56
46
  }
57
- async function installHttpPlugin(name, endpoint, authEnv, scope) {
58
- const transport = validateHttpInstall(name, endpoint, authEnv);
59
- const scopeRootPath = scope === 'project' ? ensureProjectScopeRoot() : userScopeRoot();
60
- const root = join(scopeRootPath, 'plugins', name);
61
- if (pathExists(root) && readPluginManifest(root)?.transport?.kind !== 'http') {
62
- throw general(`plugin "${name}" already exists at ${root} and is not an HTTP-transport plugin`);
47
+ function invocationTransport(bundle) {
48
+ return { kind: 'http', endpoint: new URL(bundle.endpoint).origin, ...(bundle.authEnv !== undefined ? { authEnv: bundle.authEnv } : {}) };
49
+ }
50
+ function stagedPath(stagingRoot, relative) {
51
+ const path = resolve(stagingRoot, relative);
52
+ if (path === stagingRoot || !path.startsWith(stagingRoot + sep)) {
53
+ throw general(`bundle member path escapes the staging directory: ${relative}`);
63
54
  }
64
- if (pathExists(root) && resolveHttpPluginManifestStore({ root, commands: 'commands.json' }) === null) {
65
- unsafeHttpManifestPath(name, 'commands.json');
55
+ return path;
56
+ }
57
+ function writeStagedBundle(stagingRoot, manifest, bundle) {
58
+ atomicWriteJson(stagedPath(stagingRoot, '.crouter-plugin/plugin.json'), manifest);
59
+ for (const directory of bundle.directories)
60
+ ensureDir(stagedPath(stagingRoot, directory.path));
61
+ writeFileSync(stagedPath(stagingRoot, 'commands.json'), bundle.commandsBytes);
62
+ for (const document of bundle.memory) {
63
+ const target = stagedPath(stagingRoot, document.path);
64
+ ensureDir(resolve(target, '..'));
65
+ writeFileSync(target, document.bytes);
66
66
  }
67
- const fetched = await fetchHttpPluginManifest({
68
- name,
69
- endpoint: transport.endpoint,
70
- ...(transport.authEnv !== undefined ? { authEnv: transport.authEnv } : {}),
71
- });
67
+ }
68
+ function validateStagedBundle(name, scope, root, manifest) {
69
+ const staged = { name, scope, root, manifest, enabled: true };
70
+ const validation = validatePluginCommands(staged, new Set(SUBTREE_NAMES));
71
+ if (validation.issues.length > 0) {
72
+ throw general(`bundle staged package for "${name}" is invalid`, { issues: validation.issues });
73
+ }
74
+ }
75
+ function isSourceInstalled(plugin) {
76
+ return plugin.sourceMarketplace !== undefined || isGitRepo(plugin.root) || isSymlink(plugin.root);
77
+ }
78
+ function rejectLegacyHttpPlugin(name) {
79
+ throw general(`HTTP plugin "${name}" uses the removed commands-only endpoint format`, { next: `Run \`crtr pkg plugin remove ${name}\`, then reinstall it with \`crtr pkg plugin install --name ${name} --endpoint <archive-url>\`.` });
80
+ }
81
+ function existingBundleRoot(name, scope, root) {
82
+ if (!pathExists(root))
83
+ return undefined;
84
+ const existing = findPluginByName(name, scope);
85
+ if (existing?.manifest.bundle !== undefined)
86
+ return existing;
87
+ if (existing?.manifest.transport?.kind === 'http' && existing !== undefined && !isSourceInstalled(existing))
88
+ rejectLegacyHttpPlugin(name);
89
+ throw general(`plugin "${name}" already exists at ${root}; run \`crtr pkg plugin remove ${name}\` before installing the archive plugin.`);
90
+ }
91
+ async function replaceBundlePlugin(name, bundleSource, scope, options) {
92
+ const fetchTransport = validateHttpInstall(name, bundleSource.endpoint, bundleSource.authEnv);
93
+ const bundle = { endpoint: fetchTransport.endpoint, ...(fetchTransport.authEnv !== undefined ? { authEnv: fetchTransport.authEnv } : {}) };
94
+ const transport = invocationTransport(bundle);
95
+ const scopeRootPath = scope === 'project' ? ensureProjectScopeRoot() : userScopeRoot();
96
+ const root = join(scopeRootPath, 'plugins', name);
97
+ existingBundleRoot(name, scope, root);
98
+ const fetched = await fetchHttpPluginBundle({ name, endpoint: bundle.endpoint, ...(bundle.authEnv !== undefined ? { authEnv: bundle.authEnv } : {}) });
72
99
  if (fetched.status !== 200) {
73
- const message = `HTTP plugin install failed for "${name}": ${fetched.message}`;
100
+ const message = `HTTP plugin bundle fetch failed for "${name}": ${fetched.message}`;
74
101
  if (fetched.status === 'auth_env_missing')
75
102
  throw usage(message);
76
103
  if (fetched.status === 'cli_unreachable')
77
104
  throw network(message);
78
105
  throw general(message);
79
106
  }
80
- ensureScopeInitialized(scope, scopeRootPath);
81
- atomicWriteJson(pluginManifestPath(root), {
107
+ const validated = await validatePluginBundle(fetched.raw, { reservedCoreNames: new Set(SUBTREE_NAMES) });
108
+ if (validated.bundle === undefined)
109
+ throw general(`HTTP plugin bundle for "${name}" is invalid`, { issues: validated.issues });
110
+ const version = createHash('sha256').update(fetched.raw).digest('hex').slice(0, 12);
111
+ const manifest = {
82
112
  name,
113
+ version,
83
114
  commands: 'commands.json',
84
115
  transport,
85
- });
86
- const store = resolveHttpPluginManifestStore({ root, commands: 'commands.json' });
87
- if (store === null)
88
- unsafeHttpManifestPath(name, 'commands.json');
89
- writeHttpPluginManifest(store, fetched.raw);
116
+ bundle,
117
+ };
118
+ const tmpRoot = join(scopeRootPath, 'tmp');
119
+ const staging = join(tmpRoot, `${name}.${process.pid}`);
120
+ const previous = `${staging}.prev`;
121
+ if (pathExists(previous))
122
+ throw general(`cannot replace plugin "${name}": prior interrupted replacement remains at ${previous}`);
123
+ ensureDir(tmpRoot);
124
+ ensureDir(join(scopeRootPath, 'plugins'));
125
+ removePath(staging);
126
+ try {
127
+ ensureDir(staging);
128
+ writeStagedBundle(staging, manifest, validated.bundle);
129
+ validateStagedBundle(name, scope, staging, manifest);
130
+ let movedPrevious = false;
131
+ if (pathExists(root)) {
132
+ renameSync(root, previous);
133
+ movedPrevious = true;
134
+ }
135
+ try {
136
+ renameSync(staging, root);
137
+ }
138
+ catch (error) {
139
+ if (movedPrevious)
140
+ renameSync(previous, root);
141
+ throw error;
142
+ }
143
+ if (movedPrevious)
144
+ removePath(previous);
145
+ }
146
+ finally {
147
+ removePath(staging);
148
+ }
149
+ ensureScopeInitialized(scope, scopeRootPath);
90
150
  updateConfig(scope, (cfg) => {
91
- cfg.plugins[name] = { enabled: true };
151
+ cfg.plugins[name] = { enabled: options.enable ? true : (cfg.plugins[name]?.enabled ?? true), version };
152
+ });
153
+ updateState(scope, (state) => {
154
+ if (state.plugins[name] === undefined)
155
+ state.plugins[name] = {};
156
+ state.plugins[name].last_updated = nowIso();
92
157
  });
93
158
  const commands = commandReport(name, scope);
94
- return { name, scope, path: root, transport: 'http', ...(commands !== undefined ? { commands } : {}) };
159
+ if (commands === undefined)
160
+ throw general(`bundle plugin "${name}" has no staged command report`);
161
+ return { name, scope, path: root, transport: 'http', version, docs: validated.bundle.memory.length, commands };
162
+ }
163
+ async function installHttpPlugin(name, endpoint, authEnv, scope) {
164
+ const source = validateHttpInstall(name, endpoint, authEnv);
165
+ return replaceBundlePlugin(name, { endpoint: source.endpoint, ...(source.authEnv !== undefined ? { authEnv: source.authEnv } : {}) }, scope, { enable: true });
95
166
  }
96
167
  function classifyInstallRef(raw) {
97
168
  if (raw.startsWith('./') || raw.startsWith('../') || raw.startsWith('/')) {
@@ -269,22 +340,13 @@ export function installFromMarketplace(ref, scope) {
269
340
  return { name: ref.plugin, scope, path: destPluginDir };
270
341
  }
271
342
  async function updateOnePlugin(plugin, marketplaceCache, opts) {
272
- if (plugin.manifest.transport?.kind === 'http') {
273
- const commandsPath = plugin.manifest.commands;
274
- if (typeof commandsPath !== 'string' || commandsPath.length === 0) {
275
- throw usage(`HTTP plugin "${plugin.name}" has no commands path in plugin.json; fix the manifest before updating.`);
276
- }
277
- const store = resolveHttpPluginManifestStore({ root: plugin.root, commands: commandsPath });
278
- if (store === null)
279
- unsafeHttpManifestPath(plugin.name, commandsPath);
280
- await refreshHttpPlugin({
281
- name: plugin.name,
282
- endpoint: plugin.manifest.transport.endpoint,
283
- ...(plugin.manifest.transport.authEnv !== undefined ? { authEnv: plugin.manifest.transport.authEnv } : {}),
284
- }, store);
285
- const commands = commandReport(plugin.name, plugin.scope);
286
- return { name: plugin.name, transport: 'http', updated: true, ...(commands !== undefined ? { commands } : {}) };
343
+ const sourceInstalled = isSourceInstalled(plugin);
344
+ if (!sourceInstalled && plugin.manifest.bundle !== undefined) {
345
+ const replaced = await replaceBundlePlugin(plugin.name, plugin.manifest.bundle, plugin.scope, { enable: plugin.enabled });
346
+ return { name: plugin.name, transport: 'http', updated: true, version: replaced.version, docs: replaced.docs, commands: replaced.commands };
287
347
  }
348
+ if (plugin.manifest.transport?.kind === 'http' && !sourceInstalled)
349
+ rejectLegacyHttpPlugin(plugin.name);
288
350
  let contentUpdate = { updated: false, sha: currentSha(plugin.root) ?? '' };
289
351
  let marketplaceVersion;
290
352
  if (plugin.sourceMarketplace !== undefined) {
@@ -309,7 +371,7 @@ async function updateOnePlugin(plugin, marketplaceCache, opts) {
309
371
  const commands = commandReport(plugin.name, plugin.scope);
310
372
  return {
311
373
  name: plugin.name,
312
- ...(plugin.manifest.transport?.kind === 'exec' ? { transport: 'exec' } : {}),
374
+ ...(plugin.manifest.transport !== undefined ? { transport: plugin.manifest.transport.kind } : {}),
313
375
  updated: contentUpdate.updated,
314
376
  sha: contentUpdate.sha,
315
377
  ...(commands !== undefined ? { commands } : {}),
@@ -318,13 +380,13 @@ async function updateOnePlugin(plugin, marketplaceCache, opts) {
318
380
  export const pluginInstall = defineLeaf({
319
381
  name: 'install',
320
382
  description: 'install from a ref or HTTP endpoint',
321
- whenToUse: 'installing one plugin from a marketplace ref, git URL, local path, or an HTTP command-manifest endpoint',
383
+ whenToUse: 'installing one plugin from a marketplace ref, git URL, local path, or an HTTP directory-archive endpoint',
322
384
  help: {
323
385
  name: 'pkg plugin install',
324
386
  summary: 'install a plugin from a ref or HTTP endpoint',
325
387
  params: [
326
388
  { kind: 'positional', name: 'install-ref', type: 'string', required: false, constraint: 'Plugin install ref. Provide exactly one of INSTALL-REF or --endpoint. Accepted ref forms: marketplace/plugin; git URL starting https://, ssh://, git@, file://, or ending .git; local path starting ./, ../, or /.' },
327
- { kind: 'flag', name: 'endpoint', type: 'string', required: false, constraint: 'HTTP plugin endpoint. Provide exactly one of --endpoint or INSTALL-REF. Must be an absolute https: URL; http: is permitted only for localhost, 127.0.0.1, [::1], ::1, or host.docker.internal. Credentials and fragments are rejected.' },
389
+ { kind: 'flag', name: 'endpoint', type: 'string', required: false, constraint: 'HTTP plugin directory-archive endpoint. Provide exactly one of --endpoint or INSTALL-REF. Must be an absolute https: URL; http: is permitted only for localhost, 127.0.0.1, [::1], ::1, or host.docker.internal. Credentials and fragments are rejected.' },
328
390
  { kind: 'flag', name: 'name', type: 'string', required: false, constraint: 'Required with --endpoint and rejected without it. Lowercase kebab-case plugin handle.' },
329
391
  { kind: 'flag', name: 'auth-env', type: 'string', required: false, constraint: 'Optional environment variable holding the HTTP bearer token. Accepted only with --endpoint; its value is never stored.' },
330
392
  { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Default: project if available, else user.' },
@@ -335,12 +397,14 @@ export const pluginInstall = defineLeaf({
335
397
  { name: 'scope', type: 'string', required: true, constraint: 'Scope the plugin was installed into.' },
336
398
  { name: 'path', type: 'string', required: true, constraint: 'Absolute path to the installed plugin directory.' },
337
399
  { name: 'transport', type: 'string', required: false, constraint: 'exec or http when the plugin declares commands. Always http for an --endpoint install.' },
400
+ { name: 'version', type: 'string', required: false, constraint: 'First 12 hex characters of the fetched archive SHA-256 for an --endpoint install.' },
401
+ { name: 'docs', type: 'integer', required: false, constraint: 'Memory document count written from an --endpoint archive.' },
338
402
  { name: 'commands', type: 'object', required: false, constraint: 'Present only when the plugin declares a command manifest. {mounts: string[] (accepted top-level command names now live for the next invocation), issues: object[] (typed validation issues that rejected a contribution — {code, path?, message, received, expected, next})}. Validated statically; commands are never executed.' },
339
403
  ],
340
404
  outputKind: 'object',
341
405
  effects: [
342
406
  'A ref install clones, links, or copies the plugin into the scope plugins directory and registers it with enabled=true. Marketplace installs refresh the source marketplace before resolving the plugin entry.',
343
- 'An --endpoint install validates inputs, fetches the command manifest before writing, then writes plugin.json and commands.json and enables the plugin. Reinstalling the same HTTP plugin name replaces its stored manifest and metadata; a fetch failure writes nothing.',
407
+ 'An --endpoint install fetches and validates one authenticated uncompressed tar archive before writing. It replaces the complete plugin directory with synthesized provenance and invocation metadata, commands.json, and memory docs; a fetch or validation failure preserves the prior package.',
344
408
  'If the plugin declares a command manifest, its commands go live on the next crtr invocation. Exec commands run trusted local code only when explicitly invoked; HTTP commands call their declared endpoint only when explicitly invoked.',
345
409
  ],
346
410
  },
@@ -478,7 +542,7 @@ export const pluginDisable = defineLeaf({
478
542
  export const pluginUpdate = defineLeaf({
479
543
  name: 'update',
480
544
  description: 'update installed plugin content',
481
- whenToUse: 'refreshing one named plugin or all installed plugins: HTTP plugins re-fetch their command manifest, while local plugins retain their git update behavior',
545
+ whenToUse: 'refreshing one named plugin or all installed plugins: archive plugins replace commands and memory together, while source-installed plugins retain their source update behavior',
482
546
  help: {
483
547
  name: 'pkg plugin update',
484
548
  summary: 'refresh one or all installed plugins',
@@ -486,10 +550,10 @@ export const pluginUpdate = defineLeaf({
486
550
  { kind: 'flag', name: 'name', type: 'string', required: false, constraint: 'Plugin name to update. Omit to update all installed plugins.' },
487
551
  ],
488
552
  output: [
489
- { name: 'updated', type: 'object[]', required: true, constraint: 'One entry per plugin processed: {name, transport?, updated, sha?, commands?}. HTTP plugins report transport=http and replace commands.json after an authenticated refetch; sha is present for git updates. commands is present only for plugins declaring a command manifest: {mounts: string[] (accepted top-level command names), issues: object[] ({code, path?, message, received, expected, next})} — validated statically, never executing commands.' },
553
+ { name: 'updated', type: 'object[]', required: true, constraint: 'One entry per plugin processed: {name, transport?, updated, sha?, version?, docs?, commands?, error?}. Archive plugins report transport=http and replace their complete directory after an authenticated refetch; version is the archive content identifier and docs is the written memory-document count. sha is present for git updates. A bulk update reports and skips a failed archive plugin. commands is present for validated command plugins: {mounts: string[], issues: object[]}.' },
490
554
  ],
491
555
  outputKind: 'object',
492
- effects: ['HTTP plugins unconditionally re-fetch and replace commands.json; a fetch failure exits nonzero and preserves prior bytes. Other plugins retain their git pull, version, and last_updated behavior.'],
556
+ effects: ['Archive plugins unconditionally re-fetch, validate, and replace their complete package; a named failure exits nonzero and preserves the prior package. Bulk update reports a failed archive plugin and continues. Source-installed plugins retain their source update, version, and last_updated behavior.'],
493
557
  },
494
558
  run: async (input) => {
495
559
  const name = input['name'];
@@ -503,8 +567,19 @@ export const pluginUpdate = defineLeaf({
503
567
  }
504
568
  const targets = listAllPlugins().filter((p) => p.scope !== 'builtin');
505
569
  const results = [];
506
- for (const plugin of targets)
507
- results.push(await updateOnePlugin(plugin, marketplaceCache, { strict: false }));
570
+ for (const plugin of targets) {
571
+ try {
572
+ results.push(await updateOnePlugin(plugin, marketplaceCache, { strict: false }));
573
+ }
574
+ catch (error) {
575
+ results.push({
576
+ name: plugin.name,
577
+ ...(plugin.manifest.transport !== undefined ? { transport: plugin.manifest.transport.kind } : {}),
578
+ updated: false,
579
+ error: error instanceof Error ? error.message : String(error),
580
+ });
581
+ }
582
+ }
508
583
  return { updated: results };
509
584
  },
510
585
  });
@@ -4,7 +4,7 @@ import { inspectorCore } from '../core/inspector/core.js';
4
4
  import { inspectorText } from '../core/inspector/text.js';
5
5
  import { inspectorTui } from '../core/inspector/tui.js';
6
6
  import { inTmux } from '../core/runtime/placement-tmux.js';
7
- import { runCoreView } from '../core/tui/host.js';
7
+ import { runInspector } from '../core/inspector/host.js';
8
8
  export const surfaceInspectLeaf = defineLeaf({
9
9
  name: 'inspect',
10
10
  description: 'host the native Inspector for one node',
@@ -24,7 +24,7 @@ export const surfaceInspectLeaf = defineLeaf({
24
24
  run: async (input) => {
25
25
  const node = input['node'];
26
26
  const section = (input['section'] ?? 'overview');
27
- const host = () => runCoreView(inspectorCore, inspectorTui, inspectorText, { options: { target: node, section } });
27
+ const host = () => runInspector(inspectorCore, inspectorTui, inspectorText, { options: { target: node, section } });
28
28
  // Any non-interactive invocation (pipe, redirected stdout) is a static dump.
29
29
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
30
30
  await host();
@@ -1,11 +1,7 @@
1
1
  // `crtr surface` — the screen-facing entrypoints.
2
2
  //
3
- // Groups the four surface families under one canonical noun: standalone tmux
4
- // views, live broker attachment, the split editor workspace, and the browser
5
- // shell.
3
+ // Groups the screen-facing surface families under one canonical noun.
6
4
  import { defineBranch } from '../core/command.js';
7
- import { registerView } from './view.js';
8
- import { registerWorkspace } from './workspace.js';
9
5
  import { registerWeb } from '../clients/web/web-cmd.js';
10
6
  import { registerAttach } from '../clients/attach/command.js';
11
7
  import { tmuxSpreadLeaf } from './surface-tmux-spread.js';
@@ -23,26 +19,24 @@ function namespaceForSurface(node) {
23
19
  }
24
20
  }
25
21
  export function registerSurface() {
26
- const view = registerView();
27
22
  const attach = registerAttach();
28
- const workspace = registerWorkspace();
29
23
  const web = registerWeb();
30
- for (const child of [view, attach, workspace, web]) {
24
+ for (const child of [attach, web]) {
31
25
  child.tier = 'important';
32
26
  namespaceForSurface(child);
33
27
  }
34
28
  return defineBranch({
35
29
  name: 'surface',
36
30
  rootEntry: {
37
- concept: 'screen-facing surfaces — node viewers, standalone views, live broker attachment, the editor workspace, and the browser shell',
31
+ concept: 'screen-facing surfaces — node viewers, live broker attachment, the Inspector, and the browser shell',
38
32
  desc: 'open and manage screen-facing surfaces',
39
- useWhen: 'you need a UI or presentation surface rather than a node, document, or graph operation — node-viewer navigation, standalone tmux views, live broker attachment, the split workspace layout, or the browser-hosted shell',
33
+ useWhen: 'you need a UI or presentation surface rather than a node, document, or graph operation — node-viewer navigation, live broker attachment, node inspection, or the browser-hosted shell',
40
34
  },
41
35
  help: {
42
36
  name: 'surface',
43
37
  summary: 'open and manage screen-facing surfaces',
44
- model: 'Choose `node` for navigation among node viewers. The other families select a host or layout: standalone view, broker attachment, editor workspace, browser shell, subtree spread, or adjacent editor pane.',
38
+ model: 'Choose `node` for navigation among node viewers. The other commands open a broker attachment, node Inspector, browser shell, subtree spread, or adjacent editor pane.',
45
39
  },
46
- children: [registerSurfaceNode(), view, attach, workspace, web, surfaceInspectLeaf, surfaceReloadLeaf, tmuxSpreadLeaf, surfaceEditLeaf],
40
+ children: [registerSurfaceNode(), attach, web, surfaceInspectLeaf, surfaceReloadLeaf, tmuxSpreadLeaf, surfaceEditLeaf],
47
41
  });
48
42
  }