@north-light/crouter 0.3.198 → 0.3.199

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 (314) hide show
  1. package/dist/api/client.d.ts +18 -18
  2. package/dist/api/client.js +29 -37
  3. package/dist/api/dto/broker-ops.d.ts +3 -1
  4. package/dist/api/dto/broker.d.ts +13 -2
  5. package/dist/api/dto/broker.js +4 -4
  6. package/dist/api/dto/human.d.ts +6 -5
  7. package/dist/api/dto/inbox.d.ts +81 -34
  8. package/dist/api/dto/nodes.d.ts +8 -2
  9. package/dist/api/dto/profiles.d.ts +23 -0
  10. package/dist/api/dto/profiles.js +2 -2
  11. package/dist/api/dto/worktree.d.ts +3 -5
  12. package/dist/api/routes.d.ts +3 -5
  13. package/dist/api/routes.js +4 -6
  14. package/dist/builtin-memory/00-runtime-base.md +6 -6
  15. package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
  16. package/dist/builtin-memory/02-lifecycle/00-terminal.md +3 -3
  17. package/dist/builtin-memory/04-orchestration-kernel.md +6 -6
  18. package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
  19. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +2 -2
  20. package/dist/builtin-memory/05-kinds/review/00-base.md +2 -2
  21. package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -1
  22. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +1 -1
  23. package/dist/builtin-memory/insights/capture.md +2 -2
  24. package/dist/builtin-memory/insights/init.md +3 -3
  25. package/dist/builtin-memory/internal/INDEX.md +1 -1
  26. package/dist/builtin-memory/internal/memory-loading.md +1 -1
  27. package/dist/builtin-memory/internal/nodes-and-canvas.md +2 -2
  28. package/dist/builtin-memory/internal/plugins.md +59 -2
  29. package/dist/builtin-memory/internal/storage-tiers.md +3 -1
  30. package/dist/builtin-memory/spec/roadmap.md +2 -2
  31. package/dist/builtin-memory/testing.md +1 -1
  32. package/dist/clients/attach/chrome/bash-jobs.js +3 -3
  33. package/dist/clients/attach/render/chat-view.d.ts +26 -1
  34. package/dist/clients/attach/render/chat-view.js +61 -11
  35. package/dist/clients/attach/render/page-block.d.ts +34 -0
  36. package/dist/clients/attach/render/page-block.js +226 -0
  37. package/dist/clients/attach/session/whip.d.ts +2 -0
  38. package/dist/clients/attach/session/whip.js +2 -0
  39. package/dist/clients/attach/viewer.js +1419 -993
  40. package/dist/clients/conversation/projection.js +18 -3
  41. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +9 -6
  42. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +13 -21
  43. package/dist/clients/inbox/controller.js +10 -16
  44. package/dist/clients/inbox/page-adapter.d.ts +1 -3
  45. package/dist/clients/inbox/page-adapter.js +3 -4
  46. package/dist/clients/inbox/resolve.d.ts +1 -1
  47. package/dist/clients/inbox/resolve.js +3 -3
  48. package/dist/clients/inbox/review/document-surface.js +3 -1
  49. package/dist/clients/inbox/review/state.d.ts +2 -1
  50. package/dist/clients/inbox/review/state.js +5 -16
  51. package/dist/clients/inbox/tui/input.js +37 -19
  52. package/dist/clients/inbox/tui/panel.js +5 -31
  53. package/dist/clients/inbox/tui/render.d.ts +11 -0
  54. package/dist/clients/inbox/tui/render.js +71 -27
  55. package/dist/clients/inbox/tui/slots.d.ts +3 -1
  56. package/dist/clients/inbox/tui/slots.js +16 -12
  57. package/dist/clients/inbox/tui/types.d.ts +2 -7
  58. package/dist/clients/inbox/tui.js +2 -2
  59. package/dist/commands/__tests__/human.test.js +71 -114
  60. package/dist/commands/__tests__/node-message.test.js +14 -0
  61. package/dist/commands/attention.js +4 -4
  62. package/dist/commands/canvas-snapshot.js +1 -1
  63. package/dist/commands/canvas.js +1 -1
  64. package/dist/commands/dashboard.js +1 -1
  65. package/dist/commands/human/{html.d.ts → components.d.ts} +1 -1
  66. package/dist/commands/human/components.js +77 -0
  67. package/dist/commands/human/feedback.d.ts +2 -0
  68. package/dist/commands/human/feedback.js +108 -0
  69. package/dist/commands/human/prompts.d.ts +13 -5
  70. package/dist/commands/human/prompts.js +160 -97
  71. package/dist/commands/human/queue.js +57 -88
  72. package/dist/commands/human/shared.d.ts +2 -12
  73. package/dist/commands/human/shared.js +17 -11
  74. package/dist/commands/human.js +29 -21
  75. package/dist/commands/memory/origin.js +2 -2
  76. package/dist/commands/node/bash.js +4 -4
  77. package/dist/commands/node/inspect.js +3 -3
  78. package/dist/commands/node/lifecycle.js +1 -1
  79. package/dist/commands/node/message.js +2 -2
  80. package/dist/commands/node-worktree.js +8 -8
  81. package/dist/commands/pkg/browse.js +1 -1
  82. package/dist/commands/pkg/plugin-manage.js +129 -10
  83. package/dist/commands/profile/delete.js +41 -15
  84. package/dist/commands/profile.js +1 -1
  85. package/dist/commands/push.js +1 -1
  86. package/dist/commands/surface/node/focus.js +29 -14
  87. package/dist/commands/surface-edit.js +3 -3
  88. package/dist/commands/surface-inbox.d.ts +2 -0
  89. package/dist/commands/{human/inbox.js → surface-inbox.js} +14 -18
  90. package/dist/commands/surface.js +2 -1
  91. package/dist/commands/sys/doctor.js +60 -3
  92. package/dist/commands/sys/feedback.js +79 -25
  93. package/dist/commands/sys/settings.js +1 -1
  94. package/dist/core/__tests__/cron-broker-capacity.test.js +1 -1
  95. package/dist/core/__tests__/extension-abort.test.js +5 -2
  96. package/dist/core/__tests__/fixtures/fake-engine.d.ts +13 -2
  97. package/dist/core/__tests__/fixtures/fake-engine.js +47 -3
  98. package/dist/core/__tests__/human-cancel-guard.test.js +31 -10
  99. package/dist/core/__tests__/human-deliver.test.js +31 -26
  100. package/dist/core/__tests__/human-node-not-supervised.test.js +1 -1
  101. package/dist/core/__tests__/plugin-page-components.test.js +157 -0
  102. package/dist/core/__tests__/seam/dormancy-release.test.js +40 -0
  103. package/dist/core/__tests__/serial/flagship-lifecycle.test.js +2 -2
  104. package/dist/core/__tests__/serial/human-deliver-e2e.test.js +12 -6
  105. package/dist/core/__tests__/serial/live-mutation.test.js +1 -1
  106. package/dist/core/__tests__/serial/tmux-surface.test.js +4 -2
  107. package/dist/core/__tests__/serial/worktree.test.js +24 -198
  108. package/dist/core/__tests__/session-cycles.test.js +22 -0
  109. package/dist/core/__tests__/stop-guard.test.js +4 -4
  110. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +19 -4
  111. package/dist/core/bash-jobs.d.ts +6 -0
  112. package/dist/core/bash-jobs.js +10 -0
  113. package/dist/core/canvas/__tests__/attention.test.js +8 -5
  114. package/dist/core/canvas/__tests__/render-remote.test.js +5 -5
  115. package/dist/core/canvas/attention.js +8 -6
  116. package/dist/core/canvas/browse/model.d.ts +8 -2
  117. package/dist/core/canvas/browse/model.js +11 -4
  118. package/dist/core/canvas/canvas.d.ts +7 -0
  119. package/dist/core/canvas/canvas.js +37 -0
  120. package/dist/core/canvas/crons.d.ts +9 -0
  121. package/dist/core/canvas/crons.js +51 -0
  122. package/dist/core/canvas/node-order.d.ts +22 -1
  123. package/dist/core/canvas/node-order.js +26 -1
  124. package/dist/core/canvas/render-source.d.ts +5 -0
  125. package/dist/core/canvas/render-source.js +1 -0
  126. package/dist/core/canvas/types.d.ts +9 -3
  127. package/dist/core/command-plugins/bundle.d.ts +6 -1
  128. package/dist/core/command-plugins/bundle.js +26 -13
  129. package/dist/core/command.js +2 -1
  130. package/dist/core/config.d.ts +47 -1
  131. package/dist/core/config.js +137 -4
  132. package/dist/core/help.js +1 -1
  133. package/dist/core/human/__tests__/page-catalog.test.js +4 -0
  134. package/dist/core/human/__tests__/page-tickets.test.js +65 -52
  135. package/dist/core/human/__tests__/page.test.js +56 -98
  136. package/dist/core/human/__tests__/serial/inbox-core.test.js +6 -6
  137. package/dist/core/human/answer-text.js +3 -3
  138. package/dist/core/human/answer.d.ts +6 -4
  139. package/dist/core/human/answer.js +4 -10
  140. package/dist/core/human/component-docs.d.ts +11 -7
  141. package/dist/core/human/component-docs.js +361 -88
  142. package/dist/core/human/convention.d.ts +17 -3
  143. package/dist/core/human/convention.js +36 -5
  144. package/dist/core/human/feedback-companion.d.ts +20 -0
  145. package/dist/core/human/feedback-companion.js +98 -0
  146. package/dist/core/human/feedback.d.ts +65 -0
  147. package/dist/core/human/feedback.js +116 -0
  148. package/dist/core/human/page-catalog.d.ts +40 -5
  149. package/dist/core/human/page-catalog.js +102 -30
  150. package/dist/core/human/page-errors.d.ts +4 -0
  151. package/dist/core/human/page-errors.js +7 -0
  152. package/dist/core/human/page-eval.d.ts +20 -0
  153. package/dist/core/human/page-eval.js +123 -0
  154. package/dist/core/human/page-schema.d.ts +23 -191
  155. package/dist/core/human/page-schema.js +60 -89
  156. package/dist/core/human/page-synth.d.ts +1 -1
  157. package/dist/core/human/page-synth.js +15 -18
  158. package/dist/core/human/page.d.ts +12 -27
  159. package/dist/core/human/page.js +142 -474
  160. package/dist/core/human/root.d.ts +6 -2
  161. package/dist/core/human/root.js +12 -4
  162. package/dist/core/human/scan.d.ts +3 -4
  163. package/dist/core/human/scan.js +16 -15
  164. package/dist/core/human/summary.d.ts +1 -2
  165. package/dist/core/human/summary.js +2 -2
  166. package/dist/core/human/tickets.d.ts +20 -14
  167. package/dist/core/human/tickets.js +91 -31
  168. package/dist/core/human/types.d.ts +10 -2
  169. package/dist/core/preview-registry.js +8 -10
  170. package/dist/core/profiles/default-binding.d.ts +4 -0
  171. package/dist/core/profiles/default-binding.js +24 -0
  172. package/dist/core/profiles/deletion-reservation.d.ts +8 -0
  173. package/dist/core/profiles/deletion-reservation.js +38 -0
  174. package/dist/core/profiles/manifest.d.ts +3 -0
  175. package/dist/core/profiles/manifest.js +12 -0
  176. package/dist/core/profiles/select.js +2 -2
  177. package/dist/core/review/realize.js +3 -3
  178. package/dist/core/review/store.d.ts +6 -0
  179. package/dist/core/review/store.js +31 -0
  180. package/dist/core/runtime/bearings.d.ts +0 -4
  181. package/dist/core/runtime/bearings.js +4 -62
  182. package/dist/core/runtime/bin-contributions.d.ts +44 -0
  183. package/dist/core/runtime/bin-contributions.js +186 -0
  184. package/dist/core/runtime/broker/client-registry.d.ts +4 -0
  185. package/dist/core/runtime/broker/client-registry.js +13 -1
  186. package/dist/core/runtime/broker/extension-abort.d.ts +1 -1
  187. package/dist/core/runtime/broker/extension-abort.js +4 -2
  188. package/dist/core/runtime/broker/fault-retry.js +4 -0
  189. package/dist/core/runtime/broker/frame-dispatch.d.ts +3 -1
  190. package/dist/core/runtime/broker/frame-dispatch.js +5 -6
  191. package/dist/core/runtime/broker/read-ops.d.ts +1 -1
  192. package/dist/core/runtime/broker/read-ops.js +2 -2
  193. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  194. package/dist/core/runtime/broker/rebind.js +6 -1
  195. package/dist/core/runtime/broker-extension-render.js +19 -0
  196. package/dist/core/runtime/broker-protocol.d.ts +14 -0
  197. package/dist/core/runtime/broker.d.ts +1 -1
  198. package/dist/core/runtime/broker.js +17 -6
  199. package/dist/core/runtime/front-door-env.d.ts +5 -0
  200. package/dist/core/runtime/front-door-env.js +16 -0
  201. package/dist/core/runtime/front-door.d.ts +1 -5
  202. package/dist/core/runtime/front-door.js +2 -5
  203. package/dist/core/runtime/host.d.ts +1 -1
  204. package/dist/core/runtime/invocation.d.ts +6 -0
  205. package/dist/core/runtime/invocation.js +10 -0
  206. package/dist/core/runtime/kickoff.js +34 -0
  207. package/dist/core/runtime/launch.d.ts +2 -6
  208. package/dist/core/runtime/node-read.js +4 -1
  209. package/dist/core/runtime/nodes.js +2 -0
  210. package/dist/core/runtime/promote.d.ts +1 -0
  211. package/dist/core/runtime/promote.js +3 -1
  212. package/dist/core/runtime/session-cycles.d.ts +6 -0
  213. package/dist/core/runtime/session-cycles.js +15 -1
  214. package/dist/core/runtime/session-visibility.d.ts +17 -8
  215. package/dist/core/runtime/session-visibility.js +19 -10
  216. package/dist/core/runtime/spawn-env.d.ts +9 -1
  217. package/dist/core/runtime/spawn-env.js +62 -2
  218. package/dist/core/runtime/stop-guard.d.ts +2 -2
  219. package/dist/core/runtime/stop-guard.js +2 -2
  220. package/dist/core/runtime/stop-signals.d.ts +1 -1
  221. package/dist/core/runtime/stop-signals.js +2 -2
  222. package/dist/core/runtime/tmux-bindings.js +1 -1
  223. package/dist/core/session-model/session-state.d.ts +4 -3
  224. package/dist/core/session-model/session-state.js +14 -1
  225. package/dist/core/user-settings.d.ts +21 -2
  226. package/dist/core/user-settings.js +32 -11
  227. package/dist/core/worktree.d.ts +15 -45
  228. package/dist/core/worktree.js +59 -261
  229. package/dist/daemon/api/__tests__/seam/profile-delete.test.d.ts +1 -0
  230. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +386 -0
  231. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  232. package/dist/daemon/api/handlers/broker-ops.js +9 -5
  233. package/dist/daemon/api/handlers/feedback-comments.d.ts +2 -0
  234. package/dist/daemon/api/handlers/feedback-comments.js +207 -0
  235. package/dist/daemon/api/handlers/human.js +24 -20
  236. package/dist/daemon/api/handlers/inbox.d.ts +10 -0
  237. package/dist/daemon/api/handlers/inbox.js +39 -115
  238. package/dist/daemon/api/handlers/profiles.js +11 -29
  239. package/dist/daemon/api/map.d.ts +6 -1
  240. package/dist/daemon/api/map.js +23 -0
  241. package/dist/daemon/api/server.js +3 -1
  242. package/dist/daemon/companion-retire.d.ts +2 -0
  243. package/dist/daemon/companion-retire.js +33 -0
  244. package/dist/daemon/cron-run.js +14 -16
  245. package/dist/daemon/human/finish.d.ts +12 -7
  246. package/dist/daemon/human/finish.js +101 -38
  247. package/dist/daemon/human/sweep.js +5 -1
  248. package/dist/daemon/profile-delete.d.ts +7 -0
  249. package/dist/daemon/profile-delete.js +306 -0
  250. package/dist/daemon/reconcilers/broker-supervision.js +3 -1
  251. package/dist/daemon/review/deliver.js +3 -3
  252. package/dist/daemon/review/finish.d.ts +0 -2
  253. package/dist/daemon/review/finish.js +1 -29
  254. package/dist/pi-extensions/__tests__/canvas-bash-valve.test.js +56 -1
  255. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +4 -4
  256. package/dist/pi-extensions/canvas-bash-valve.js +19 -5
  257. package/dist/pi-extensions/canvas-inbox-watcher.js +1 -1
  258. package/dist/pi-extensions/canvas-review-boundary.d.ts +4 -0
  259. package/dist/pi-extensions/canvas-review-boundary.js +18 -9
  260. package/dist/pi-extensions/canvas-stophook.js +4 -4
  261. package/dist/shared/generated-context.js +2 -2
  262. package/dist/types.d.ts +44 -2
  263. package/dist/types.js +7 -2
  264. package/package.json +4 -4
  265. package/runtime.lock.json +5 -33
  266. package/dist/builtin-memory/init.md +0 -38
  267. package/dist/builtin-memory/plan.md +0 -19
  268. package/dist/builtin-memory/spec.md +0 -19
  269. package/dist/commands/human/doc.d.ts +0 -2
  270. package/dist/commands/human/doc.js +0 -91
  271. package/dist/commands/human/html.js +0 -81
  272. package/dist/commands/human/inbox.d.ts +0 -2
  273. package/dist/core/human/__tests__/html-markdown.test.js +0 -52
  274. package/dist/core/human/__tests__/page-render.test.js +0 -66
  275. package/dist/core/human/html-markdown.d.ts +0 -3
  276. package/dist/core/human/html-markdown.js +0 -288
  277. package/dist/core/human/page-render.d.ts +0 -4
  278. package/dist/core/human/page-render.js +0 -105
  279. package/dist/pages/bundle.css +0 -1
  280. package/dist/pages/bundle.js +0 -1778
  281. package/dist/pages/comments.d.ts +0 -72
  282. package/dist/pages/comments.js +0 -176
  283. package/dist/pages/controls.d.ts +0 -98
  284. package/dist/pages/controls.js +0 -261
  285. package/dist/pages/elements/cards.d.ts +0 -28
  286. package/dist/pages/elements/cards.js +0 -915
  287. package/dist/pages/elements/chart.d.ts +0 -23
  288. package/dist/pages/elements/chart.js +0 -664
  289. package/dist/pages/elements/options.d.ts +0 -30
  290. package/dist/pages/elements/options.js +0 -742
  291. package/dist/pages/elements/pages.d.ts +0 -30
  292. package/dist/pages/elements/pages.js +0 -377
  293. package/dist/pages/elements/slot.d.ts +0 -26
  294. package/dist/pages/elements/slot.js +0 -112
  295. package/dist/pages/elements/table.d.ts +0 -36
  296. package/dist/pages/elements/table.js +0 -1043
  297. package/dist/pages/elements/text.d.ts +0 -31
  298. package/dist/pages/elements/text.js +0 -1175
  299. package/dist/pages/entry.d.ts +0 -8
  300. package/dist/pages/entry.js +0 -8
  301. package/dist/pages/host.d.ts +0 -134
  302. package/dist/pages/host.js +0 -165
  303. package/dist/pages/readonly.d.ts +0 -24
  304. package/dist/pages/readonly.js +0 -31
  305. package/dist/pages/register.d.ts +0 -2
  306. package/dist/pages/register.js +0 -3
  307. package/dist/pages/responses.d.ts +0 -37
  308. package/dist/pages/responses.js +0 -56
  309. package/dist/pages/slot-config.d.ts +0 -36
  310. package/dist/pages/slot-config.js +0 -50
  311. package/dist/pages/types.d.ts +0 -98
  312. package/dist/pages/types.js +0 -23
  313. /package/dist/{core/human/__tests__/html-markdown.test.d.ts → commands/__tests__/node-message.test.d.ts} +0 -0
  314. /package/dist/core/{human/__tests__/page-render.test.d.ts → __tests__/plugin-page-components.test.d.ts} +0 -0
@@ -13,21 +13,19 @@ function uniqueIds(items, ctx, label) {
13
13
  seen.add(item.id);
14
14
  });
15
15
  }
16
+ // Response comments qualify the answer itself, so anchors name only answerable structure:
17
+ // one of a question's options, or a table row. Feedback on rendered page content — including
18
+ // the question text itself — is a ticket-level feedback comment (feedback.ts), not part of
19
+ // any response.
16
20
  export const commentAnchorSchema = z.discriminatedUnion('kind', [
17
- z.object({ kind: z.literal('whole') }).strict(),
18
21
  z.object({ kind: z.literal('option'), optionId: itemIdSchema }).strict(),
19
22
  z.object({ kind: z.literal('row'), rowId: itemIdSchema }).strict(),
20
- z.object({ kind: z.literal('column'), columnId: itemIdSchema }).strict(),
21
- z.object({ kind: z.literal('card'), cardId: itemIdSchema }).strict(),
22
- z.object({ kind: z.literal('range'), start: z.number().int().nonnegative(), end: z.number().int().nonnegative(), quote: z.string() }).strict().superRefine((anchor, ctx) => {
23
- if (anchor.end < anchor.start)
24
- ctx.addIssue({ code: 'custom', path: ['end'], message: 'range end must be greater than or equal to start' });
25
- }),
26
23
  ]);
27
24
  export const commentSchema = z.object({ id: z.string().min(1), anchor: commentAnchorSchema, text: z.string() }).strict();
28
25
  export const optionSchema = z.object({ id: itemIdSchema, label: z.string().min(1), description: z.string().optional() }).strict();
29
26
  export const optionsConfigSchema = z.object({
30
27
  label: z.string().optional(),
28
+ body: z.string().optional(),
31
29
  options: z.array(optionSchema).min(1).superRefine((items, ctx) => uniqueIds(items, ctx, 'option')),
32
30
  mode: z.enum(['single', 'multi']),
33
31
  allowFreetext: z.boolean().optional(),
@@ -35,49 +33,38 @@ export const optionsConfigSchema = z.object({
35
33
  freetextPlaceholder: z.string().optional(),
36
34
  }).strict();
37
35
  export const optionsResponseSchema = z.object({ selectedOptionIds: z.array(itemIdSchema), comments: z.array(commentSchema), freetext: z.string().optional() }).strict();
38
- // `singleLine` swaps the writing surface for one compact form field — a subject line, a name,
39
- // a URL. It is an input by definition, so it is always editable and `editable: false` on it is
40
- // an authoring mistake rather than a read-only one-liner.
41
- export const textConfigSchema = z.object({ label: z.string().optional(), initialText: z.string(), editable: z.boolean().optional(), placeholder: z.string().optional(), singleLine: z.boolean().optional() }).strict().superRefine((config, ctx) => {
42
- if (config.singleLine === true && config.editable === false)
43
- ctx.addIssue({ code: 'custom', path: ['editable'], message: 'single-line text is always editable; drop editable: false' });
44
- });
45
- export const textResponseSchema = z.object({ text: z.string(), edited: z.boolean(), comments: z.array(commentSchema) }).strict();
36
+ // Text is a writing surface, always: its whole point is the string the user hands back, so
37
+ // there is no read-only mode. `singleLine` only swaps the multi-line surface for one compact
38
+ // form field — a subject line, a name, a URL.
39
+ export const textConfigSchema = z.object({ label: z.string().optional(), initialText: z.string(), placeholder: z.string().optional(), singleLine: z.boolean().optional() }).strict();
40
+ export const textResponseSchema = z.object({ text: z.string(), edited: z.boolean() }).strict();
46
41
  export const tableColumnSchema = z.object({ id: itemIdSchema, label: z.string().min(1), align: z.enum(['left', 'right']).optional(), mono: z.boolean().optional() }).strict();
47
42
  export const tableCellSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
48
43
  export const tableRowSchema = z.object({ id: itemIdSchema, cells: z.record(z.string(), tableCellSchema) }).strict();
49
44
  export const tableRowsSchema = z.array(tableRowSchema).superRefine((items, ctx) => uniqueIds(items, ctx, 'row'));
50
45
  const tableConfigFields = {
51
46
  label: z.string().optional(),
47
+ body: z.string().optional(),
52
48
  columns: z.array(tableColumnSchema).min(1).superRefine((items, ctx) => uniqueIds(items, ctx, 'column')),
53
49
  rows: tableRowsSchema.optional(),
54
50
  rowSelect: selectModeSchema.default('none'),
55
51
  columnSelect: selectModeSchema.default('none'),
56
52
  };
57
- /** Stored table config: its data is always embedded. */
53
+ /** Table config: its data is always embedded. */
58
54
  export const tableConfigSchema = z.object(tableConfigFields).strict();
59
- /** Authored table config: `source` is resolved before the manifest is stored. */
60
- export const authoredTableConfigSchema = z.object({ ...tableConfigFields, source: z.string() }).strict().superRefine((config, ctx) => {
61
- if (config.rows !== undefined)
62
- ctx.addIssue({ code: 'custom', message: 'table rows and source are mutually exclusive' });
63
- });
64
55
  export const tableResponseSchema = z.object({ selectedRowIds: z.array(itemIdSchema), selectedColumnIds: z.array(itemIdSchema), comments: z.array(commentSchema) }).strict();
65
56
  export const cardSchema = z.object({ id: itemIdSchema, title: z.string().min(1), subtitle: z.string().optional(), body: z.string().optional(), tag: z.string().optional() }).strict();
66
57
  export const cardsSchema = z.array(cardSchema).superRefine((items, ctx) => uniqueIds(items, ctx, 'card'));
67
58
  const cardsConfigFields = {
68
59
  label: z.string().optional(),
60
+ body: z.string().optional(),
69
61
  cards: cardsSchema.optional(),
70
62
  mode: z.enum(['single', 'multi']),
71
63
  columns: z.union([z.literal(2), z.literal(3)]).optional(),
72
64
  };
73
- /** Stored cards config: its data is always embedded. */
65
+ /** Cards config: its data is always embedded. */
74
66
  export const cardsConfigSchema = z.object(cardsConfigFields).strict();
75
- /** Authored cards config: `source` is resolved before the manifest is stored. */
76
- export const authoredCardsConfigSchema = z.object({ ...cardsConfigFields, source: z.string() }).strict().superRefine((config, ctx) => {
77
- if (config.cards !== undefined)
78
- ctx.addIssue({ code: 'custom', message: 'cards data and source are mutually exclusive' });
79
- });
80
- export const cardsResponseSchema = z.object({ selectedCardIds: z.array(itemIdSchema), comments: z.array(commentSchema) }).strict();
67
+ export const cardsResponseSchema = z.object({ selectedCardIds: z.array(itemIdSchema) }).strict();
81
68
  export const chartSeriesSchema = z.object({ field: z.string().min(1), label: z.string().optional() }).strict();
82
69
  export const chartDataRowsSchema = z.array(z.record(z.string(), z.unknown()));
83
70
  const chartConfigFields = {
@@ -87,26 +74,27 @@ const chartConfigFields = {
87
74
  title: z.string().optional(),
88
75
  data: chartDataRowsSchema.optional(),
89
76
  };
90
- /** Stored chart config: its data is always embedded. */
77
+ /** Chart config: its data is always embedded. */
91
78
  export const chartConfigSchema = z.object(chartConfigFields).strict();
92
- /** Authored chart config: `source` is resolved before the manifest is stored. */
93
- export const authoredChartConfigSchema = z.object({ ...chartConfigFields, source: z.string() }).strict().superRefine((config, ctx) => {
94
- if (config.data !== undefined)
95
- ctx.addIssue({ code: 'custom', message: 'chart data and source are mutually exclusive' });
96
- });
97
- const sourceSchema = z.object({ sessionName: z.string().optional(), askedBy: z.string().optional(), blockedSince: z.string().optional(), profileName: z.string().optional(), nodeId: z.string().optional() }).strict();
79
+ const sourceSchema = z.object({ sessionName: z.string().optional(), askedBy: z.string().optional(), emittedAt: z.string().datetime({ offset: true }).optional(), profileName: z.string().optional(), nodeId: z.string().optional() }).strict();
80
+ const deliverySchema = z.object({ placement: z.enum(['inline', 'panel']), inbox: z.boolean(), reply: z.boolean() }).strict();
98
81
  const rawSlotSchema = z.object({ id: idSchema.optional(), kind: z.string().min(1), step: z.number().int().nonnegative(), config: jsonObjectSchema, unvalidated: z.literal(true).optional(), display: z.literal(true).optional() }).strict();
99
82
  const rawPageManifestSchema = z.object({
100
- schema: z.literal('crtr.page/v1'),
101
- dialect: z.enum(['md', 'html']),
83
+ schema: z.literal('crtr.page/v2'),
84
+ dialect: z.enum(['jsx', 'html']),
102
85
  title: z.string().trim().min(1),
103
86
  subtitle: z.string().optional(),
104
- placement: z.enum(['inline', 'panel']),
105
- document: z.enum(['page.md', 'page.html']),
87
+ delivery: deliverySchema,
88
+ document: z.enum(['page.tsx', 'page.html']),
106
89
  steps: z.number().int().positive(),
107
90
  slots: z.array(rawSlotSchema),
108
91
  source: sourceSchema.optional(),
109
- }).strict();
92
+ }).strict().superRefine((manifest, ctx) => {
93
+ if ((manifest.dialect === 'jsx') !== (manifest.document === 'page.tsx'))
94
+ ctx.addIssue({ code: 'custom', path: ['document'], message: 'document must agree with dialect' });
95
+ if (manifest.dialect === 'html' && (manifest.steps !== 1 || manifest.slots.length !== 0))
96
+ ctx.addIssue({ code: 'custom', path: ['slots'], message: 'HTML pages have exactly one step and no slots' });
97
+ });
110
98
  export const BUILTIN_PAGE_CONFIG_SCHEMAS = {
111
99
  options: optionsConfigSchema,
112
100
  text: textConfigSchema,
@@ -114,13 +102,6 @@ export const BUILTIN_PAGE_CONFIG_SCHEMAS = {
114
102
  cards: cardsConfigSchema,
115
103
  chart: chartConfigSchema,
116
104
  };
117
- const AUTHORED_PAGE_CONFIG_SCHEMAS = {
118
- options: optionsConfigSchema,
119
- text: textConfigSchema,
120
- table: z.union([tableConfigSchema, authoredTableConfigSchema]),
121
- cards: z.union([cardsConfigSchema, authoredCardsConfigSchema]),
122
- chart: z.union([chartConfigSchema, authoredChartConfigSchema]),
123
- };
124
105
  export const BUILTIN_PAGE_RESPONSE_SCHEMAS = {
125
106
  options: optionsResponseSchema,
126
107
  text: textResponseSchema,
@@ -145,10 +126,8 @@ export function isResponseBearingSlot(slot) {
145
126
  }
146
127
  function validateManifest(parsed, productComponents, authored) {
147
128
  const manifest = rawPageManifestSchema.parse(parsed);
148
- if (manifest.document !== (manifest.dialect === 'md' ? 'page.md' : 'page.html'))
149
- throw new Error(`page document "${manifest.document}" does not match ${manifest.dialect} dialect`);
150
- if (manifest.dialect === 'md' && manifest.steps !== 1)
151
- throw new Error(`md page steps must be 1; received ${manifest.steps}`);
129
+ if (!authored && manifest.dialect === 'html')
130
+ return manifest;
152
131
  const seen = new Set();
153
132
  const slots = manifest.slots.map((raw, index) => {
154
133
  if (raw.step >= manifest.steps)
@@ -159,29 +138,38 @@ function validateManifest(parsed, productComponents, authored) {
159
138
  throw new Error(`built-in slot kind "${raw.kind}" cannot be unvalidated`);
160
139
  if (raw.display === true)
161
140
  throw new Error(`built-in slot kind "${raw.kind}" cannot set display: true`);
162
- const result = (authored ? AUTHORED_PAGE_CONFIG_SCHEMAS : BUILTIN_PAGE_CONFIG_SCHEMAS)[raw.kind].safeParse(raw.config);
141
+ const result = BUILTIN_PAGE_CONFIG_SCHEMAS[raw.kind].safeParse(raw.config);
163
142
  if (!result.success)
164
143
  throw new Error(`invalid config for slot ${raw.id === undefined ? `#${index}` : `"${raw.id}"`} (${raw.kind}): ${issueText(result.error)}`);
144
+ // Authoring-time only: persisted manifests predate this rule and must keep reading.
145
+ if (authored && raw.kind === 'options') {
146
+ const options = result.data;
147
+ const slotName = raw.id === undefined ? `#${index}` : `"${raw.id}"`;
148
+ if ((options.label ?? '').trim() === '')
149
+ throw new Error(`slot ${slotName} (options): label is required — the question itself, drawn as the bold first line`);
150
+ if ((options.body ?? '').trim() === '')
151
+ throw new Error(`slot ${slotName} (options): body is required — the context under the question a label cannot carry`);
152
+ }
165
153
  slot = { ...(raw.id === undefined ? {} : { id: raw.id }), kind: raw.kind, step: raw.step, config: result.data };
166
154
  }
167
155
  else {
168
- const component = productPageComponent(raw.kind, productComponents);
169
- if (component === undefined)
156
+ const component = productComponents === undefined ? undefined : productPageComponent(raw.kind, productComponents);
157
+ if (authored && component === undefined)
170
158
  throw new Error(`unregistered page slot kind "${raw.kind}" at slot #${index}`);
171
159
  if (raw.unvalidated !== true)
172
- throw new Error(`registered product slot kind "${raw.kind}" must set unvalidated: true`);
173
- if (!authored && raw.display !== (component.display === true ? true : undefined))
174
- throw new Error(component.display === true
175
- ? `display product slot kind "${raw.kind}" must set display: true`
176
- : `non-display product slot kind "${raw.kind}" cannot set display: true`);
177
- if (authored && raw.display === true && component.display !== true)
178
- throw new Error(`non-display product slot kind "${raw.kind}" cannot set display: true`);
179
- slot = { ...(raw.id === undefined ? {} : { id: raw.id }), kind: raw.kind, step: raw.step, config: raw.config, unvalidated: true, ...(component.display === true ? { display: true } : {}) };
160
+ throw new Error(`registered page slot kind "${raw.kind}" must set unvalidated: true`);
161
+ if (!authored)
162
+ slot = { ...(raw.id === undefined ? {} : { id: raw.id }), kind: raw.kind, step: raw.step, config: raw.config, unvalidated: true, ...(raw.display === true ? { display: true } : {}) };
163
+ else {
164
+ if (raw.display === true && component?.display !== true)
165
+ throw new Error(`non-display page slot kind "${raw.kind}" cannot set display: true`);
166
+ slot = { ...(raw.id === undefined ? {} : { id: raw.id }), kind: raw.kind, step: raw.step, config: raw.config, unvalidated: true, ...(component?.display === true ? { display: true } : {}) };
167
+ }
180
168
  }
181
169
  if (isResponseBearingSlot(slot) && slot.id === undefined) {
182
170
  throw new Error(slot.unvalidated === true
183
- ? `product slot kind "${slot.kind}" at slot #${index} requires an id="…" attribute on its <crtr-slot> element`
184
- : `response-bearing slot kind "${slot.kind}" at slot #${index} requires an id="…" attribute on its element`);
171
+ ? `product slot kind "${slot.kind}" at slot #${index} requires an id prop`
172
+ : `response-bearing slot kind "${slot.kind}" at slot #${index} requires an id prop`);
185
173
  }
186
174
  if (slot.id !== undefined) {
187
175
  if (seen.has(slot.id))
@@ -192,26 +180,25 @@ function validateManifest(parsed, productComponents, authored) {
192
180
  });
193
181
  return { ...manifest, slots };
194
182
  }
195
- /** Validate a persisted manifest. Source paths are rejected: pages render only embedded data. */
196
- export function validatePageManifest(parsed, productComponents = []) {
197
- return validateManifest(parsed, productComponents, false);
183
+ /** Validate a persisted manifest. Publish-time validation made its slots authoritative, so reads do not resolve a component catalog. */
184
+ export function validatePageManifest(parsed) {
185
+ return validateManifest(parsed, undefined, false);
198
186
  }
199
- /** Validate an authored manifest before submit. Source paths are resolved by `snapshotPageSources`. */
187
+ /** Validate a manifest derived from an authored page, where the display flag comes from the registration rather than the source. */
200
188
  export function validateAuthoredPageManifest(parsed, productComponents = []) {
201
189
  return validateManifest(parsed, productComponents, true);
202
190
  }
203
- export function createPageManifestSchema(productComponents = []) {
191
+ export function createPageManifestSchema() {
204
192
  return z.custom((value) => {
205
193
  try {
206
- validatePageManifest(value, productComponents);
194
+ validatePageManifest(value);
207
195
  return true;
208
196
  }
209
197
  catch {
210
198
  return false;
211
199
  }
212
- }, { error: 'invalid page manifest' }).transform((value) => validatePageManifest(value, productComponents));
200
+ }, { error: 'invalid page manifest' }).transform((value) => validatePageManifest(value));
213
201
  }
214
- /** Built-in-only manifest schema; product-aware callers use createPageManifestSchema. */
215
202
  export const pageManifestSchema = createPageManifestSchema();
216
203
  function assertUnique(values, slotId, field) {
217
204
  if (new Set(values).size !== values.length)
@@ -221,30 +208,16 @@ function validateComments(slot, comments) {
221
208
  const config = slot.config;
222
209
  for (const comment of comments) {
223
210
  const anchor = comment.anchor;
224
- if (anchor.kind === 'whole')
225
- continue;
226
211
  if (slot.kind === 'options' && anchor.kind === 'option') {
227
212
  if (!config.options.some((option) => option.id === anchor.optionId))
228
213
  throw new Error(`slot "${slot.id}" comment names unknown option id "${anchor.optionId}"`);
229
214
  continue;
230
215
  }
231
- if (slot.kind === 'text' && anchor.kind === 'range')
232
- continue;
233
216
  if (slot.kind === 'table' && anchor.kind === 'row') {
234
217
  if (!(config.rows ?? []).some((row) => row.id === anchor.rowId))
235
218
  throw new Error(`slot "${slot.id}" comment names unknown row id "${anchor.rowId}"`);
236
219
  continue;
237
220
  }
238
- if (slot.kind === 'table' && anchor.kind === 'column') {
239
- if (!config.columns.some((column) => column.id === anchor.columnId))
240
- throw new Error(`slot "${slot.id}" comment names unknown column id "${anchor.columnId}"`);
241
- continue;
242
- }
243
- if (slot.kind === 'cards' && anchor.kind === 'card') {
244
- if (!(config.cards ?? []).some((card) => card.id === anchor.cardId))
245
- throw new Error(`slot "${slot.id}" comment names unknown card id "${anchor.cardId}"`);
246
- continue;
247
- }
248
221
  throw new Error(`slot "${slot.id}" does not allow comment anchor kind "${anchor.kind}"`);
249
222
  }
250
223
  }
@@ -281,7 +254,6 @@ function parseResponse(slot, raw) {
281
254
  const result = textResponseSchema.safeParse(raw);
282
255
  if (!result.success)
283
256
  throw new Error(`invalid response for slot "${slot.id}": ${issueText(result.error)}`);
284
- validateComments(slot, result.data.comments);
285
257
  return result.data;
286
258
  }
287
259
  if (slot.kind === 'table') {
@@ -319,7 +291,6 @@ function parseResponse(slot, raw) {
319
291
  throw new Error(`slot "${slot.id}" selects unknown card id "${id}"`);
320
292
  if (config.mode === 'single' && response.selectedCardIds.length > 1)
321
293
  throw new Error(`slot "${slot.id}" is single-select but received ${response.selectedCardIds.length} card ids`);
322
- validateComments(slot, response.comments);
323
294
  return response;
324
295
  }
325
296
  throw new Error(`slot "${slot.id}" kind "${slot.kind}" does not accept a response`);
@@ -344,5 +315,5 @@ function validateResponses(manifest, raw, partial) {
344
315
  }
345
316
  /** Validate a complete final response map. */
346
317
  export function validatePageResponses(manifest, responses) { return validateResponses(manifest, responses, false); }
347
- /** Validate an autosaved response map, permitting omitted response-bearing slots. */
318
+ /** Validate an autosaved response map, permitting omitted response-bearing components. */
348
319
  export function validatePartialPageResponses(manifest, responses) { return validateResponses(manifest, responses, true); }
@@ -1,4 +1,4 @@
1
- /** Build a complete HTML page from title, subtitle, and body for internal producers. */
1
+ /** Build a complete TSX page from title, subtitle, and body for internal producers. */
2
2
  export declare function synthesizedPageDocument(title: string, subtitle: string, body: string, responseBearing: boolean): string;
3
3
  /** Materialize an internally generated document into a private temp dir; the caller removes it after submission. */
4
4
  export declare function writeSynthesizedPage(document: string): {
@@ -1,33 +1,30 @@
1
1
  import { join } from 'node:path';
2
2
  import { mkdtempSync, writeFileSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
- function escapeHtml(value) {
5
- return value.replace(/[&<>"']/g, (character) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[character]);
6
- }
7
- function bodyHtml(body) {
4
+ /** Text reaches JSX as a string expression, so arbitrary bytes need no markup escaping. */
5
+ function jsxText(value) { return `{${JSON.stringify(value)}}`; }
6
+ function bodyJsx(body) {
8
7
  if (body === '')
9
8
  return '';
10
- return `<p>${escapeHtml(body).replace(/\r?\n/g, '<br>')}</p>`;
9
+ const lines = body.replace(/\r\n/g, '\n').split('\n');
10
+ return ` <p className="whitespace-pre-wrap">${lines.map(jsxText).join('<br />')}</p>\n`;
11
11
  }
12
- /** Build a complete HTML page from title, subtitle, and body for internal producers. */
12
+ /** Build a complete TSX page from title, subtitle, and body for internal producers. */
13
13
  export function synthesizedPageDocument(title, subtitle, body, responseBearing) {
14
- const contents = bodyHtml(body);
15
- const interactive = responseBearing
16
- ? `<crtr-pages><crtr-page><crtr-text id="response"><script type="application/json">{"initialText":"","editable":true}</script></crtr-text></crtr-page></crtr-pages>`
17
- : '';
18
- return `<!doctype html>
19
- <html><head>
20
- <meta name="crtr-page-title" content="${escapeHtml(title)}">
21
- <meta name="crtr-page-subtitle" content="${escapeHtml(subtitle)}">
22
- </head><body>
23
- ${contents}${contents === '' || interactive === '' ? '' : '\n'}${interactive}
24
- </body></html>
14
+ const interactive = responseBearing ? ` <UserText id="response" initialText="" />\n` : '';
15
+ const subtitleProp = subtitle === '' ? '' : ` subtitle=${jsxText(subtitle)}`;
16
+ return `export default function SynthesizedPage() {
17
+ return (
18
+ <Page title=${jsxText(title)}${subtitleProp}>
19
+ ${bodyJsx(body)}${interactive} </Page>
20
+ );
21
+ }
25
22
  `;
26
23
  }
27
24
  /** Materialize an internally generated document into a private temp dir; the caller removes it after submission. */
28
25
  export function writeSynthesizedPage(document) {
29
26
  const dir = mkdtempSync(join(tmpdir(), 'crtr-human-page-'));
30
- const path = join(dir, 'page.html');
27
+ const path = join(dir, 'page.tsx');
31
28
  writeFileSync(path, document, { encoding: 'utf8', mode: 0o600 });
32
29
  return { dir, path };
33
30
  }
@@ -1,29 +1,14 @@
1
1
  import type { ProductPageComponents } from '../../types.js';
2
- import { type AuthoredPageManifest, type PageManifest, type PageSource } from './page-schema.js';
3
- /** Dialects retained in persisted manifests. New page authoring is HTML-only. */
4
- export type PageDialect = 'md' | 'html';
5
- export type AuthoredPageDialect = 'html';
6
- export type PageSourceBlock = {
7
- kind: 'prose';
8
- markdown: string;
9
- } | {
10
- kind: 'slot';
11
- slotIndex: number;
12
- };
13
- export type PageSourceProjection = PageSourceBlock[];
14
- /** A page failed authoring or validation; the caller can report it as bad page input. */
15
- export declare class PageAuthoringError extends Error {
16
- constructor(message: string);
17
- }
18
- /** Derive the transport manifest from one authored HTML page document. */
19
- export declare function derivePageManifestFromDocument(document: string, dialect: AuthoredPageDialect, productComponents?: ProductPageComponents, source?: PageSource): AuthoredPageManifest;
20
- /** Derive the transport manifest from one authored HTML page source file. */
21
- export declare function derivePageManifest(sourceFile: string, dialect: AuthoredPageDialect, productComponents?: ProductPageComponents, source?: PageSource): AuthoredPageManifest;
22
- /** Read source files into their built-in slots, returning a self-contained stored manifest. */
23
- export declare function snapshotPageSources(manifest: AuthoredPageManifest, productComponents?: ProductPageComponents): PageManifest;
24
- /** Replace every authored slot config with its stored, self-contained config for runtime rendering. */
25
- export declare function embedPageSlotConfigs(document: string, manifest: PageManifest): string;
2
+ import { type PageDelivery, type PageManifest, type PageSource } from './page-schema.js';
3
+ import { PageAuthoringError } from './page-errors.js';
4
+ export { PageAuthoringError };
5
+ /** Compile one authored TSX page to the CommonJS module the Gateway evaluates.
6
+ * Registry names stay free identifiers; the Gateway supplies them at eval. */
7
+ export declare function compilePage(document: string): string;
8
+ /** Derive the transport manifest from one authored TSX page document. */
9
+ export declare function derivePageManifestFromDocument(document: string, productComponents?: ProductPageComponents, source?: PageSource, delivery?: PageDelivery): PageManifest;
10
+ export declare function deriveHtmlPageManifest(document: string, source?: PageSource, delivery?: PageDelivery): PageManifest;
11
+ /** Derive the transport manifest from one authored TSX page source file. */
12
+ export declare function derivePageManifest(sourceFile: string, productComponents?: ProductPageComponents, source?: PageSource, delivery?: PageDelivery): PageManifest;
26
13
  /** Read and validate page.json from a ticket directory. */
27
- export declare function parsePage(dir: string, productComponents?: ProductPageComponents): PageManifest;
28
- /** Project authored source for local rendering and verify its slot references against the manifest. */
29
- export declare function parsePageSource(document: string, manifest: PageManifest, productComponents?: ProductPageComponents): PageSourceProjection;
14
+ export declare function parsePage(dir: string): PageManifest;