@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
@@ -1,54 +1,51 @@
1
1
  import assert from 'node:assert/strict';
2
- import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
2
  import test from 'node:test';
6
- import { derivePageManifest, parsePageSource } from '../page.js';
3
+ import { derivePageManifestFromDocument } from '../page.js';
7
4
  import { isResponseBearingSlot, validatePageManifest, validatePageResponses, validatePartialPageResponses } from '../page-schema.js';
8
- function withSource(name, source, run) {
9
- const dir = mkdtempSync(join(tmpdir(), 'crtr-page-test-'));
10
- try {
11
- const path = join(dir, name);
12
- writeFileSync(path, source);
13
- run(path);
14
- }
15
- finally {
16
- rmSync(dir, { recursive: true, force: true });
17
- }
5
+ const OPTIONS = '<UserQuestion id="choice" label="Choose an option" body="One of these ships tonight." mode="single" options={[{ id: "yes", label: "Yes" }]} />';
6
+ function page(body, props = 'title="Test"') {
7
+ return `export default function Page_() {\n return (\n <Page ${props}>\n ${body}\n </Page>\n );\n}\n`;
18
8
  }
19
- const htmlHead = '<!doctype html><html><head><meta name="crtr-page-title" content="Test"></head><body>';
20
- const htmlTail = '</body></html>';
21
- const optionsScript = '<script type="application/json">{"label":"Choose an option","mode":"single","options":[{"id":"yes","label":"Yes"}]}</script>';
22
- function deriveHtml(body, head = htmlHead) {
23
- let manifest;
24
- withSource('input.html', `${head}${body}${htmlTail}`, (path) => { manifest = derivePageManifest(path, 'html'); });
25
- return manifest;
26
- }
27
- function expectHtmlError(body, pattern, head = htmlHead) {
28
- withSource('input.html', `${head}${body}${htmlTail}`, (path) => assert.throws(() => derivePageManifest(path, 'html'), pattern));
29
- }
30
- test('html dialect derives document-order slots and wrapper steps', () => {
31
- const body = `<crtr-pages><crtr-page><section><crtr-options id="choice">${optionsScript}</crtr-options></section></crtr-page><crtr-page><crtr-chart><script type="application/json">{"kind":"bar","x":"day","y":[{"field":"count"}]}</script></crtr-chart></crtr-page></crtr-pages>`;
32
- const manifest = deriveHtml(body, '<!doctype html><html placement="inline"><head><meta name="crtr-page-title" content="HTML"><meta name="crtr-page-subtitle" content="Two steps"><meta name="crtr-page-placement" content="inline"></head><body>');
33
- assert.equal(manifest.title, 'HTML');
34
- assert.equal(manifest.placement, 'inline');
9
+ test('jsx pages derive page props, steps, and document-order slots', () => {
10
+ const manifest = derivePageManifestFromDocument(page(`<Step>${OPTIONS}</Step>\n <Step><Chart kind="bar" x="day" y={[{ field: "count" }]} /></Step>`, 'title="JSX" subtitle="Two steps"'));
11
+ assert.equal(manifest.title, 'JSX');
12
+ assert.equal(manifest.subtitle, 'Two steps');
13
+ assert.deepEqual(manifest.delivery, { placement: 'inline', inbox: false, reply: false });
35
14
  assert.equal(manifest.steps, 2);
36
- assert.deepEqual(manifest.slots.map(({ kind, step }) => ({ kind, step })), [{ kind: 'options', step: 0 }, { kind: 'chart', step: 1 }]);
15
+ assert.deepEqual(manifest.slots.map(({ kind, step, id }) => ({ kind, step, id })), [
16
+ { kind: 'options', step: 0, id: 'choice' },
17
+ { kind: 'chart', step: 1, id: undefined },
18
+ ]);
19
+ });
20
+ test('a page without steps is one step, and a slot config computed at render time still reaches the manifest', () => {
21
+ const manifest = derivePageManifestFromDocument(page('<UserText id="note" label="Add a note" initialText="" />'));
22
+ assert.equal(manifest.steps, 1);
23
+ assert.deepEqual(manifest.slots, [{ id: 'note', kind: 'text', step: 0, config: { label: 'Add a note', initialText: '' } }]);
24
+ // The manifest is harvested by rendering the page, so mapped data, helper components,
25
+ // and hook state are all present; handlers are dropped because a manifest is JSON.
26
+ const computed = derivePageManifestFromDocument(`const ROWS = [{ id: 'a', label: 'A' }, { id: 'b', label: 'B' }];
27
+ function Pick({ rows }) { return <UserQuestion id="picks" label="Pick" body="Rows come from data." mode="single" options={rows.map((r) => ({ id: r.id, label: r.label }))} onSelect={() => 1} />; }
28
+ export default function Computed() { const [title] = React.useState('Computed'); return <Page title={title}><Pick rows={ROWS} /></Page>; }
29
+ `);
30
+ assert.equal(computed.title, 'Computed');
31
+ assert.deepEqual(computed.slots, [{ id: 'picks', kind: 'options', step: 0, config: { label: 'Pick', body: 'Rows come from data.', mode: 'single', options: [{ id: 'a', label: 'A' }, { id: 'b', label: 'B' }] } }]);
32
+ });
33
+ test('a page that cannot render is rejected with the reason', () => {
34
+ assert.throws(() => derivePageManifestFromDocument(page(OPTIONS, 'title=""')), /nonempty title prop/);
35
+ assert.throws(() => derivePageManifestFromDocument(page(OPTIONS, 'title="T" placement="drawer"')), /placement is not authored/);
36
+ assert.throws(() => derivePageManifestFromDocument('function Page_() { return <Page title="T" />; }\n'), /must `export default` a component function/);
37
+ assert.throws(() => derivePageManifestFromDocument('export default function Page_() { return (<><Page title="A" /><Page title="B" /></>); }'), /exactly one is allowed/);
38
+ assert.throws(() => derivePageManifestFromDocument('export default () => <Page title="T"><Mystery /></Page>;'), /Mystery is not defined/);
39
+ assert.throws(() => derivePageManifestFromDocument('export default async () => <Page title="T" />;'), /async/);
40
+ });
41
+ test('module plumbing is rejected with the in-scope teaching', () => {
42
+ const importing = `import React from 'react';\n${page(OPTIONS)}`;
43
+ assert.throws(() => derivePageManifestFromDocument(importing), /page source uses import: .*already in scope/s);
44
+ const requiring = `const x = require('./data.json');\n${page(OPTIONS)}`;
45
+ assert.throws(() => derivePageManifestFromDocument(requiring), /page source uses require\(\)/);
37
46
  });
38
- test('html wrapper rejects multiple crtr-pages', () => expectHtmlError('<crtr-pages><crtr-page></crtr-page></crtr-pages><crtr-pages><crtr-page></crtr-page></crtr-pages>', /more than one <crtr-pages>/));
39
- test('html wrapper rejects crtr-page outside crtr-pages', () => expectHtmlError('<crtr-page></crtr-page>', /<crtr-page> outside <crtr-pages>/));
40
- test('html wrapper rejects empty crtr-pages', () => expectHtmlError('<crtr-pages></crtr-pages>', /empty <crtr-pages>/));
41
- test('html wrapper rejects a response-bearing element outside a step with the fix', () => expectHtmlError(`<crtr-options id="choice">${optionsScript}</crtr-options>`, /response-bearing element <crtr-options>[\s\S]*<crtr-pages><crtr-page>…<\/crtr-page><\/crtr-pages>/));
42
- test('html wrapper rejects nested crtr-pages', () => expectHtmlError('<crtr-pages><crtr-page><crtr-pages><crtr-page></crtr-page></crtr-pages></crtr-page></crtr-pages>', /nested <crtr-pages>/));
43
- test('html metadata enforces cardinality, known names, and placement content', () => {
44
- const duplicateTitle = '<!doctype html><html><head><meta name="crtr-page-title" content="A"><meta name="crtr-page-title" content="B"></head><body>';
45
- const duplicateSubtitle = '<!doctype html><html><head><meta name="crtr-page-title" content="A"><meta name="crtr-page-subtitle" content="A"><meta name="crtr-page-subtitle" content="B"></head><body>';
46
- const unknown = '<!doctype html><html><head><meta name="crtr-page-title" content="A"><meta name="crtr-page-extra" content="x"></head><body>';
47
- const badPlacement = '<!doctype html><html><head><meta name="crtr-page-title" content="A"><meta name="crtr-page-placement" content="drawer"></head><body>';
48
- expectHtmlError('', /Expected exactly one <meta name="crtr-page-title">, found 2/, duplicateTitle);
49
- expectHtmlError('', /Expected at most one <meta name="crtr-page-subtitle">, found 2/, duplicateSubtitle);
50
- expectHtmlError('', /unknown page metadata element <meta name="crtr-page-extra">/, unknown);
51
- expectHtmlError('', /content must be exactly inline or panel/, badPlacement);
47
+ test('a page that does not compile is reported with its location', () => {
48
+ assert.throws(() => derivePageManifestFromDocument('export default function Page_() { return (<Page title="Broken">; }'), /page does not compile: .*page\.tsx:\d+:\d+/s);
52
49
  });
53
50
  test('the response-bearing predicate handles table selection and catalog edges', () => {
54
51
  const slot = (kind, config, unvalidated) => ({ kind, step: 0, config, ...(unvalidated ? { unvalidated } : {}) });
@@ -57,66 +54,27 @@ test('the response-bearing predicate handles table selection and catalog edges',
57
54
  assert.equal(isResponseBearingSlot(slot('chart', { kind: 'bar', x: 'x', y: [{ field: 'y' }] })), false);
58
55
  assert.equal(isResponseBearingSlot(slot('product-kind', {}, true)), true);
59
56
  });
60
- test('display product slots derive as non-response-bearing without interactive structure', () => {
57
+ test('product components are authored under their PascalCase tag', () => {
61
58
  const displayComponent = [{ kind: 'nl-thread', display: true }];
62
- const displayBody = '<crtr-slot kind="nl-thread"><script type="application/json">{"messages":[]}</script></crtr-slot>';
63
- let displayManifest;
64
- withSource('input.html', `${htmlHead}${displayBody}${htmlTail}`, (path) => { displayManifest = derivePageManifest(path, 'html', displayComponent); });
65
- assert.deepEqual(displayManifest.slots, [{ kind: 'nl-thread', step: 0, config: { messages: [] }, unvalidated: true, display: true }]);
66
- assert.deepEqual(validatePageManifest(displayManifest, displayComponent).slots, displayManifest.slots);
67
- assert.equal(isResponseBearingSlot(displayManifest.slots[0]), false);
68
- const responseBody = '<crtr-slot kind="product-input"><script type="application/json">{}</script></crtr-slot>';
69
- withSource('input.html', `${htmlHead}${responseBody}${htmlTail}`, (path) => {
70
- assert.throws(() => derivePageManifest(path, 'html', [{ kind: 'product-input' }]), /product slot kind "product-input" at slot #0 requires an id="…" attribute on its <crtr-slot> element/);
71
- });
59
+ const manifest = derivePageManifestFromDocument(page('<NlThread messages={[]} />'), displayComponent);
60
+ assert.deepEqual(manifest.slots, [{ kind: 'nl-thread', step: 0, config: { messages: [] }, unvalidated: true, display: true }]);
61
+ assert.deepEqual(validatePageManifest(manifest).slots, manifest.slots);
62
+ assert.equal(isResponseBearingSlot(manifest.slots[0]), false);
63
+ assert.throws(() => derivePageManifestFromDocument(page('<ProductInput />'), [{ kind: 'product-input' }]), /product slot kind "product-input" at slot #0 requires an id prop/);
64
+ });
65
+ test('a question requires its label and body at authoring time', () => {
66
+ assert.throws(() => derivePageManifestFromDocument(page('<UserQuestion id="choice" body="Context." mode="single" options={[{ id: "yes", label: "Yes" }]} />')), /slot "choice" \(options\): label is required/);
67
+ assert.throws(() => derivePageManifestFromDocument(page('<UserQuestion id="choice" label="Choose" mode="single" options={[{ id: "yes", label: "Yes" }]} />')), /slot "choice" \(options\): body is required/);
72
68
  });
73
69
  test('multi-response pages require a label on every response-bearing slot', () => {
74
- expectHtmlError(`<crtr-pages><crtr-page><crtr-options id="choice"><script type="application/json">{"mode":"single","options":[{"id":"yes","label":"Yes"}]}</script></crtr-options><crtr-text id="note"><script type="application/json">{"label":"Add a note","initialText":""}</script></crtr-text></crtr-page></crtr-pages>`, /response-bearing slot "choice" requires a nonempty config\.label/);
75
- expectHtmlError(`<crtr-pages><crtr-page><crtr-options id="choice"><script type="application/json">{"label":"Choose","mode":"single","options":[{"id":"yes","label":"Yes"}]}</script></crtr-options><crtr-table id="table"><script type="application/json">{"label":"Pick a row","columns":[{"id":"name","label":"Name"}],"rows":[{"id":"one","cells":{"name":"One"}}],"rowSelect":"single","caption":"old"}</script></crtr-table></crtr-page></crtr-pages>`, /invalid config for slot "table"/);
70
+ assert.throws(() => derivePageManifestFromDocument(page(`<UserText id="first" initialText="" />\n <UserText id="note" label="Add a note" initialText="" />`)), /response-bearing slot "first" requires a nonempty config\.label/);
71
+ assert.throws(() => derivePageManifestFromDocument(page(`${OPTIONS}\n <UserTable id="table" label="Pick a row" columns={[{ id: "name", label: "Name" }]} rows={[{ id: "one", cells: { name: "One" } }]} rowSelect="single" caption="old" />`)), /invalid config for slot "table"/);
76
72
  });
77
73
  test('final and partial response validation share slot-addressed rules', () => {
78
- const manifest = deriveHtml(`<crtr-pages><crtr-page><crtr-options id="choice">${optionsScript}</crtr-options><crtr-text id="note"><script type="application/json">{"label":"Add a note","initialText":""}</script></crtr-text></crtr-page></crtr-pages>`);
74
+ const manifest = derivePageManifestFromDocument(page(`${OPTIONS}\n <UserText id="note" label="Add a note" initialText="" />`));
79
75
  assert.deepEqual(validatePartialPageResponses(manifest, { choice: { selectedOptionIds: ['yes'], comments: [] } }), { choice: { selectedOptionIds: ['yes'], comments: [] } });
80
76
  assert.throws(() => validatePageResponses(manifest, { choice: { selectedOptionIds: ['yes'], comments: [] } }), /missing response-bearing slot id "note"/);
81
- assert.deepEqual(validatePageResponses(manifest, { choice: { selectedOptionIds: ['yes'], comments: [] }, note: { text: '', edited: false, comments: [] } }), { choice: { selectedOptionIds: ['yes'], comments: [] }, note: { text: '', edited: false, comments: [] } });
77
+ assert.deepEqual(validatePageResponses(manifest, { choice: { selectedOptionIds: ['yes'], comments: [] }, note: { text: '', edited: false } }), { choice: { selectedOptionIds: ['yes'], comments: [] }, note: { text: '', edited: false } });
82
78
  assert.throws(() => validatePartialPageResponses(manifest, { choice: { selectedOptionIds: ['maybe'], comments: [] } }), /unknown option id "maybe"/);
83
79
  assert.throws(() => validatePartialPageResponses(manifest, { extra: {} }), /unknown or non-response-bearing slot id "extra"/);
84
80
  });
85
- test('PageSourceProjection rejects changed inline component data', () => {
86
- const body = '<crtr-table><script type="application/json">{"columns":[{"id":"name","label":"Name"}],"rows":[{"id":"one","cells":{"name":"One"}}]}</script></crtr-table>';
87
- const manifest = deriveHtml(body);
88
- const changed = {
89
- ...manifest,
90
- slots: [{ ...manifest.slots[0], config: { columns: [{ id: 'name', label: 'Name' }], rows: [{ id: 'two', cells: { name: 'Two' } }] } }],
91
- };
92
- assert.throws(() => parsePageSource(`${htmlHead}${body}${htmlTail}`, changed), /does not match manifest slot/);
93
- });
94
- test('PageSourceProjection preserves legacy markdown replay and interleaves HTML prose', () => {
95
- const legacySource = `---
96
- title: Projection
97
- ---
98
- Leading prose.
99
-
100
- \`\`\`slot:text
101
- {"id":"first","label":"First answer","initialText":""}
102
- \`\`\`
103
-
104
- Trailing prose.
105
- `;
106
- const legacyManifest = {
107
- schema: 'crtr.page/v1', dialect: 'md', title: 'Projection', placement: 'panel', document: 'page.md', steps: 1,
108
- slots: [{ id: 'first', kind: 'text', step: 0, config: { label: 'First answer', initialText: '' } }],
109
- };
110
- assert.deepEqual(parsePageSource(legacySource, legacyManifest), [
111
- { kind: 'prose', markdown: 'Leading prose.' },
112
- { kind: 'slot', slotIndex: 0 },
113
- { kind: 'prose', markdown: 'Trailing prose.' },
114
- ]);
115
- const htmlSource = '<!doctype html><html><head><meta name="crtr-page-title" content="Test"></head><body><p>Leading prose.</p><crtr-pages><crtr-page><crtr-text id="first"><script type="application/json">{"label":"First answer","initialText":""}</script></crtr-text><p>Trailing prose.</p></crtr-page></crtr-pages></body></html>';
116
- const htmlManifest = deriveHtml('<p>Leading prose.</p><crtr-pages><crtr-page><crtr-text id="first"><script type="application/json">{"label":"First answer","initialText":""}</script></crtr-text><p>Trailing prose.</p></crtr-page></crtr-pages>');
117
- assert.deepEqual(parsePageSource(htmlSource, htmlManifest), [
118
- { kind: 'prose', markdown: '<p>Leading prose.</p>' },
119
- { kind: 'slot', slotIndex: 0 },
120
- { kind: 'prose', markdown: '<p>Trailing prose.</p>' },
121
- ]);
122
- });
@@ -12,10 +12,10 @@ const temp = mkdtempSync(join(tmpdir(), 'crtr-inbox-core-'));
12
12
  process.env['CRTR_HOME'] = temp;
13
13
  const source = join(temp, 'source.md');
14
14
  writeFileSync(source, '# Source\n');
15
- const pageSource = join(temp, 'page.html');
16
- writeFileSync(pageSource, '<!doctype html><html><head><meta name="crtr-page-title" content="A page"><meta name="crtr-page-subtitle" content="Go? requires your attention."></head><body><crtr-pages><crtr-page><crtr-text id="go"><script type="application/json">{"initialText":"","editable":true}</script></crtr-text></crtr-page></crtr-pages></body></html>');
17
- const page = (id, blockedSince) => submitPage({ dir: ticketDir(id), sourceFile: pageSource, dialect: 'html', source: { blockedSince, nodeId: 'node-1' } });
18
- const answer = { go: { text: 'yes', edited: true, comments: [] } };
15
+ const pageSource = join(temp, 'page.tsx');
16
+ writeFileSync(pageSource, 'export default () => (\n <Page title="A page" subtitle="Go? requires your attention.">\n <UserText id="go" initialText="" />\n </Page>\n);\n');
17
+ const page = (id, emittedAt) => submitPage({ dir: ticketDir(id), sourceFile: pageSource, source: { emittedAt, nodeId: 'node-1' }, delivery: { placement: 'inline', inbox: true, reply: true } });
18
+ const answer = { go: { text: 'yes', edited: true } };
19
19
  async function waitFor(paths) {
20
20
  for (let attempts = 0; !paths.every(existsSync); attempts++) {
21
21
  if (attempts > 1_000)
@@ -32,7 +32,7 @@ assert.equal(existsSync(ticketDir('bad-review')), false, 'invalid submission doe
32
32
  const prepared = ticketDir('prepared');
33
33
  mkdirSync(prepared);
34
34
  writeFileSync(join(prepared, 'asset.png'), 'prepared asset');
35
- const preparedTicket = submitPage({ dir: prepared, sourceFile: pageSource, dialect: 'html', source: { blockedSince: '2025-01-02T00:00:00.000Z', nodeId: 'node-1' } });
35
+ const preparedTicket = submitPage({ dir: prepared, sourceFile: pageSource, source: { emittedAt: '2025-01-02T00:00:00.000Z', nodeId: 'node-1' }, delivery: { placement: 'inline', inbox: true, reply: true } });
36
36
  assert.equal(preparedTicket.dir, realpathSync(prepared), 'submission accepts a crouter-precreated direct child and colocated assets');
37
37
  // Same timestamp is stable by id; progress is resumable work, never a hidden lease.
38
38
  atomicWriteJson(progressPath(newPage.dir), { kind: 'page', responses: {}, savedAt: new Date().toISOString() });
@@ -94,7 +94,7 @@ for (const [index, fixture] of rejectFixtures.entries()) {
94
94
  const protocolDir = ticketDir('stale-protocol');
95
95
  mkdirSync(protocolDir);
96
96
  writeFileSync(responsePath(protocolDir), '{}');
97
- assert.throws(() => submitPage({ dir: protocolDir, sourceFile: pageSource, dialect: 'html' }), /protocol state/, 'precreated assets may not include humanloop lifecycle state');
97
+ assert.throws(() => submitPage({ dir: protocolDir, sourceFile: pageSource }), /protocol state/, 'precreated assets may not include humanloop lifecycle state');
98
98
  const cancelDir = page('cancel-race', '2025-01-03T00:00:00.000Z').dir;
99
99
  const canceled = cancelTicket(cancelDir, { reason: 'stop' });
100
100
  assert.equal(canceled.status, 'canceled');
@@ -26,7 +26,7 @@ function groupLines(group) {
26
26
  return [`${groupName(group)}: ${group.picked.length === 0 ? 'none' : group.picked.map(item).join(', ')}`];
27
27
  }
28
28
  function commentLines(comment) {
29
- const prefix = comment.anchor.kind === 'whole' ? 'Comment: ' : `Comment on ${comment.anchor.kind === 'range' ? inline(comment.anchorLabel) : `“${comment.anchorLabel}”`}: `;
29
+ const prefix = comment.anchor.kind === 'whole' ? 'Comment: ' : `Comment on ${inline(comment.anchorLabel)}: `;
30
30
  return verbatim(prefix, comment.text);
31
31
  }
32
32
  function shape(slot) {
@@ -84,13 +84,13 @@ function slotLines(slot, totalSlots) {
84
84
  export function renderAnswerText(answer, responsePath) {
85
85
  if (answer.kind === 'acknowledgement') {
86
86
  return [
87
- `The human saw **${answer.title}** and dismissed it. The page asked for nothing, so the acknowledgement is the whole answer.`,
87
+ `The user saw **${answer.title}** and dismissed it. The page asked for nothing, so the acknowledgement is the whole answer.`,
88
88
  '',
89
89
  `Acknowledged ${answer.completedAt}. Response record: ${responsePath}`,
90
90
  ].join('\n');
91
91
  }
92
92
  const answered = answer.slots.filter((slot) => slot.state === 'answered');
93
- const lines = [`The human answered **${answer.title}**.`];
93
+ const lines = [`The user answered **${answer.title}**.`];
94
94
  for (const slot of answered)
95
95
  lines.push('', ...slotLines(slot, answer.slots.length));
96
96
  lines.push('', `Answered ${answer.completedAt}. Typed responses: ${responsePath}`);
@@ -1,4 +1,3 @@
1
- import type { ProductPageComponents } from '../../types.js';
2
1
  import { type CommentAnchor, type PageResponses, type PageSlot } from './page-schema.js';
3
2
  export type PageAnswer = {
4
3
  title: string;
@@ -34,16 +33,19 @@ export type PageAnswerGroup = {
34
33
  label: string;
35
34
  }[];
36
35
  };
36
+ /** Stored responses predating the `whole` anchor's removal still carry it; answers keep rendering them. */
37
+ export type LegacyCommentAnchor = CommentAnchor | {
38
+ kind: 'whole';
39
+ };
37
40
  export type PageAnswerComment = {
38
- anchor: CommentAnchor;
41
+ anchor: LegacyCommentAnchor;
39
42
  anchorLabel: string;
40
43
  text: string;
41
44
  };
42
45
  export interface DescribePageAnswerOptions {
43
46
  completedAt: string;
44
- productKinds?: ProductPageComponents;
45
47
  }
46
- export declare function answerCommentAnchorLabel(slot: PageSlot, anchor: CommentAnchor): string;
48
+ export declare function answerCommentAnchorLabel(slot: PageSlot, anchor: LegacyCommentAnchor): string;
47
49
  /** Derive the one shared answer model from the immutable page manifest and a response map. */
48
50
  /** `manifest` is unknown deliberately: this boundary validates persisted JSON before deriving. */
49
51
  export declare function describePageAnswer(manifest: unknown, responses: PageResponses, opts: DescribePageAnswerOptions): PageAnswer;
@@ -28,15 +28,9 @@ function slotLabel(slot) {
28
28
  }
29
29
  export function answerCommentAnchorLabel(slot, anchor) {
30
30
  if (anchor.kind === 'whole')
31
- return slotLabel(slot);
32
- if (anchor.kind === 'range')
33
- return anchor.quote;
31
+ return slotLabel(slot); // legacy stored data only; new anchors are option/row
34
32
  if (anchor.kind === 'option')
35
33
  return slot.config.options.find((option) => option.id === anchor.optionId)?.label ?? anchor.optionId;
36
- if (anchor.kind === 'card')
37
- return slot.config.cards?.find((card) => card.id === anchor.cardId)?.title ?? anchor.cardId;
38
- if (anchor.kind === 'column')
39
- return slot.config.columns.find((column) => column.id === anchor.columnId)?.label ?? anchor.columnId;
40
34
  return rowLabel(slot.config, anchor.rowId);
41
35
  }
42
36
  function describeComments(slot, response) {
@@ -65,7 +59,7 @@ function describeSlot(slot, response) {
65
59
  const text = value;
66
60
  const written = typeof text.text === 'string' ? text.text : '';
67
61
  const singleLine = slot.config.singleLine === true;
68
- return { ...base, blank: singleLine && written === '', groups: [], text: { value: written, edited: text.edited === true, ...(singleLine ? { singleLine: true } : {}) }, comments: describeComments(slot, value) };
62
+ return { ...base, blank: singleLine && written === '', groups: [], text: { value: written, edited: text.edited === true, ...(singleLine ? { singleLine: true } : {}) }, comments: [] };
69
63
  }
70
64
  if (slot.kind === 'table') {
71
65
  const config = slot.config;
@@ -80,14 +74,14 @@ function describeSlot(slot, response) {
80
74
  const config = slot.config;
81
75
  const cards = (config.cards ?? []).map((card) => ({ id: card.id, label: card.title }));
82
76
  const group = { group: 'card', mode: config.mode, total: cards.length, picked: picked(strings(value.selectedCardIds), cards) };
83
- return { ...base, blank: group.picked.length === 0, groups: [group], comments: describeComments(slot, value) };
77
+ return { ...base, blank: group.picked.length === 0, groups: [group], comments: [] };
84
78
  }
85
79
  throw new Error(`slot "${slot.id}" kind "${slot.kind}" does not accept a response`);
86
80
  }
87
81
  /** Derive the one shared answer model from the immutable page manifest and a response map. */
88
82
  /** `manifest` is unknown deliberately: this boundary validates persisted JSON before deriving. */
89
83
  export function describePageAnswer(manifest, responses, opts) {
90
- const page = validatePageManifest(manifest, opts.productKinds);
84
+ const page = validatePageManifest(manifest);
91
85
  const slots = page.slots.filter(isResponseBearingSlot).map((slot) => describeSlot(slot, hasOwn(responses, slot.id) ? responses[slot.id] : undefined));
92
86
  const answered = slots.filter((slot) => slot.state === 'answered');
93
87
  return {
@@ -1,14 +1,18 @@
1
1
  import type { PageComponentRegistration } from '../../types.js';
2
2
  export interface ComponentDoc {
3
- kind: string;
4
- tag: string;
3
+ /** Registry names this doc covers. A family (Card, CardHeader, …) shares one contract. */
4
+ names: readonly string[];
5
+ /** `structural` builds the page, `slot` is a registry component that gets its own manifest
6
+ * record (and, unless display-only, its own response), `display` is presentation only. */
7
+ group: 'structural' | 'slot' | 'display';
5
8
  selectionLine: string;
6
9
  contract: string;
7
10
  }
8
11
  export declare const BUILTIN_COMPONENT_DOCS: readonly ComponentDoc[];
9
- /** Compact catalog rows shared by `human -h` and `human html list`. */
10
- export declare const BUILTIN_COMPONENT_SELECTION_LINES: string[];
11
- export declare function componentDoc(kind: string): ComponentDoc | undefined;
12
- export declare function componentKinds(productKinds: readonly string[]): string[];
12
+ /** The structural and response-bearing rows — the ones that decide what a page can ask. `human -h` carries these;
13
+ * the display set is one line there and the full catalog is `human components list`. */
14
+ export declare const CORE_COMPONENT_SELECTION_LINES: string[];
15
+ export declare function componentDoc(name: string): ComponentDoc | undefined;
16
+ export declare function componentNames(productComponents: readonly PageComponentRegistration[]): string[];
13
17
  export declare function renderComponentCatalog(productComponents: readonly PageComponentRegistration[]): string;
14
- export declare function renderComponentContract(kind: string, productComponents: readonly PageComponentRegistration[]): string | undefined;
18
+ export declare function renderComponentContract(name: string, productComponents: readonly PageComponentRegistration[]): string | undefined;