@shoalrun/cli 0.1.0-alpha.17 → 0.1.0-alpha.19

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 (686) hide show
  1. package/AUTHORING.md +29 -0
  2. package/CHANGELOG.md +54 -0
  3. package/DEPLOYMENT-PROFILES.md +96 -5
  4. package/README.md +106 -25
  5. package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +23 -17
  6. package/agent-docs/SNAPSHOT.json +5 -5
  7. package/agent-docs/api-docs/focused-contracts.md +4 -4
  8. package/agent-docs/api-docs/generate.md +11 -11
  9. package/agent-docs/api-docs/generate.sections/add-useful-examples.md +3 -3
  10. package/agent-docs/api-docs/generate.sections/choose-generated-references-or-mdx.md +4 -4
  11. package/agent-docs/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +1 -1
  12. package/agent-docs/api-docs/generate.sections/generate-many-pages-selectively.md +2 -2
  13. package/agent-docs/api-docs/generate.sections/link-guides-to-api-references.md +1 -1
  14. package/agent-docs/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md +1 -1
  15. package/agent-docs/api-docs/generate.sections/override-generated-reference-order-in-navigation.md +4 -4
  16. package/agent-docs/api-docs/generate.sections/related-reading.md +1 -1
  17. package/agent-docs/api-docs/generate.sections/use-a-template-for-editorial-context.md +2 -2
  18. package/agent-docs/api-docs/support.md +7 -7
  19. package/agent-docs/author/add-page.md +3 -3
  20. package/agent-docs/author/agent-overview.md +3 -3
  21. package/agent-docs/author/agent-workflow.md +7 -7
  22. package/agent-docs/author/analytics.md +27 -27
  23. package/agent-docs/author/analytics.sections/adapter-exports-and-consent.md +3 -3
  24. package/agent-docs/author/analytics.sections/built-in-events.md +15 -15
  25. package/agent-docs/author/analytics.sections/configure-an-adapter.md +1 -1
  26. package/agent-docs/author/analytics.sections/custom-interactions.md +2 -2
  27. package/agent-docs/author/analytics.sections/event-format.md +2 -2
  28. package/agent-docs/author/analytics.sections/html-markdown-and-agents.md +4 -4
  29. package/agent-docs/author/analytics.sections/inspect-events-locally.md +2 -2
  30. package/agent-docs/author/analytics.sections/map-events-to-your-service.md +3 -3
  31. package/agent-docs/author/analytics.sections/posthog-example.md +3 -3
  32. package/agent-docs/author/analytics.sections/related-reading.md +1 -1
  33. package/agent-docs/author/authoring-agent.md +3 -3
  34. package/agent-docs/author/coding-agent.md +4 -4
  35. package/agent-docs/author/components/api-embeds.md +6 -6
  36. package/agent-docs/author/components/api-embeds.sections/apiexample.md +3 -3
  37. package/agent-docs/author/components/api-embeds.sections/html-markdown-and-agents.md +1 -1
  38. package/agent-docs/author/components/api-embeds.sections/related-reading.md +1 -1
  39. package/agent-docs/author/components/badge.md +2 -2
  40. package/agent-docs/author/components/callout.md +2 -2
  41. package/agent-docs/author/components/cards.md +16 -16
  42. package/agent-docs/author/components/cards.sections/add-a-lucide-icon.md +4 -4
  43. package/agent-docs/author/components/cards.sections/build-a-collection.md +7 -7
  44. package/agent-docs/author/components/cards.sections/curate-a-reading-list.md +9 -9
  45. package/agent-docs/author/components/cards.sections/html-markdown-and-agents.md +3 -3
  46. package/agent-docs/author/components/cards.sections/link-to-one-document.md +3 -3
  47. package/agent-docs/author/components/cards.sections/override-card-text.md +5 -5
  48. package/agent-docs/author/components/cards.sections/related-reading.md +3 -3
  49. package/agent-docs/author/components/code-blocks.md +2 -2
  50. package/agent-docs/author/components/collapsible.md +3 -3
  51. package/agent-docs/author/components/cookbook-chooser.md +5 -5
  52. package/agent-docs/author/components/custom/react.md +8 -8
  53. package/agent-docs/author/components/custom/react.sections/html-markdown-and-agents.md +3 -3
  54. package/agent-docs/author/components/custom/react.sections/interactive-react-example.md +2 -2
  55. package/agent-docs/author/components/custom/react.sections/registration.md +1 -1
  56. package/agent-docs/author/components/custom/react.sections/related-reading.md +1 -1
  57. package/agent-docs/author/components/custom/react.sections/share-the-model-with-the-browser.md +3 -3
  58. package/agent-docs/author/components/custom/react.sections/where-the-content-lives.md +3 -3
  59. package/agent-docs/author/components/custom.md +7 -7
  60. package/agent-docs/author/components/definition-list.md +2 -2
  61. package/agent-docs/author/components/diagrams/d2-gallery.md +2 -2
  62. package/agent-docs/author/components/diagrams/d2-gallery.sections/basic-shapes.md +2 -2
  63. package/agent-docs/author/components/diagrams/d2-gallery.sections/flows-and-structures.md +2 -2
  64. package/agent-docs/author/components/diagrams/d2-gallery.sections/html-markdown-and-agents.md +2 -2
  65. package/agent-docs/author/components/diagrams/d2-gallery.sections/layout-engines.md +2 -2
  66. package/agent-docs/author/components/diagrams/d2-gallery.sections/related-reading.md +2 -2
  67. package/agent-docs/author/components/diagrams/d2-gallery.sections/sequences-and-grids.md +2 -2
  68. package/agent-docs/author/components/diagrams/d2-gallery.sections/styles-and-code.md +2 -2
  69. package/agent-docs/author/components/diagrams/pele-gallery.md +3 -3
  70. package/agent-docs/author/components/diagrams/pele-gallery.sections/charts-and-planning.md +2 -2
  71. package/agent-docs/author/components/diagrams/pele-gallery.sections/flowchart-shapes.md +2 -2
  72. package/agent-docs/author/components/diagrams/pele-gallery.sections/flows-and-behavior.md +2 -2
  73. package/agent-docs/author/components/diagrams/pele-gallery.sections/html-markdown-and-agents.md +3 -3
  74. package/agent-docs/author/components/diagrams/pele-gallery.sections/related-reading.md +2 -2
  75. package/agent-docs/author/components/diagrams/pele-gallery.sections/specialized-diagrams.md +2 -2
  76. package/agent-docs/author/components/diagrams/pele-gallery.sections/systems-and-structures.md +2 -2
  77. package/agent-docs/author/components/diagrams.md +8 -8
  78. package/agent-docs/author/components/doc-link.md +3 -3
  79. package/agent-docs/author/components/fields.md +18 -18
  80. package/agent-docs/author/components/file-tree.md +2 -2
  81. package/agent-docs/author/components/images.md +5 -5
  82. package/agent-docs/author/components/info-hint.md +3 -3
  83. package/agent-docs/author/components/kbd.md +2 -2
  84. package/agent-docs/author/components/math.md +2 -2
  85. package/agent-docs/author/components/only.md +3 -3
  86. package/agent-docs/author/components/progress.md +3 -3
  87. package/agent-docs/author/components/steps.md +2 -2
  88. package/agent-docs/author/components/tables.md +2 -2
  89. package/agent-docs/author/components/tabs.md +5 -5
  90. package/agent-docs/author/components/timeline.md +2 -2
  91. package/agent-docs/author/components/tooltips.md +2 -2
  92. package/agent-docs/author/components/walkthroughs.md +2 -2
  93. package/agent-docs/author/components/walkthroughs.sections/attributes.md +1 -1
  94. package/agent-docs/author/components/walkthroughs.sections/build-up-code.md +1 -1
  95. package/agent-docs/author/components/walkthroughs.sections/choose-a-layout.md +2 -2
  96. package/agent-docs/author/components/walkthroughs.sections/explain-one-file.md +1 -1
  97. package/agent-docs/author/components/walkthroughs.sections/html-markdown-and-agents.md +1 -1
  98. package/agent-docs/author/components/walkthroughs.sections/related-reading.md +1 -1
  99. package/agent-docs/author/components/walkthroughs.sections/syntax.md +1 -1
  100. package/agent-docs/author/components/walkthroughs.sections/take-code-from-a-file.md +1 -1
  101. package/agent-docs/author/components.md +2 -2
  102. package/agent-docs/author/content.md +3 -3
  103. package/agent-docs/author/cookbooks.md +9 -9
  104. package/agent-docs/author/css.md +4 -4
  105. package/agent-docs/author/css.sections/borders-fields-and-navigation-tokens.md +3 -3
  106. package/agent-docs/author/css.sections/core-color-tokens.md +3 -3
  107. package/agent-docs/author/css.sections/html-markdown-and-agents.md +4 -4
  108. package/agent-docs/author/css.sections/page-attributes.md +3 -3
  109. package/agent-docs/author/css.sections/page-transitions.md +3 -3
  110. package/agent-docs/author/css.sections/responsive-behavior.md +3 -3
  111. package/agent-docs/author/css.sections/status-code-and-callout-tokens.md +3 -3
  112. package/agent-docs/author/css.sections/typography-shape-and-width-tokens.md +3 -3
  113. package/agent-docs/author/custom-metadata.md +13 -13
  114. package/agent-docs/author/custom-metadata.sections/add-a-custom-page-field.md +4 -4
  115. package/agent-docs/author/custom-metadata.sections/choose-text-for-each-surface.md +3 -3
  116. package/agent-docs/author/custom-metadata.sections/preview-changes-to-metadata-providers.md +2 -2
  117. package/agent-docs/author/custom-metadata.sections/read-metadata-from-a-project-module.md +3 -3
  118. package/agent-docs/author/custom-metadata.sections/related-reading.md +1 -1
  119. package/agent-docs/author/design-templates.md +3 -3
  120. package/agent-docs/author/design-writing-guides.md +3 -3
  121. package/agent-docs/author/frontmatter-reference.md +45 -6
  122. package/agent-docs/author/frontmatter-reference.sections/categorize-connect-and-present-the-page.md +64 -0
  123. package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +2 -2
  124. package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +2 -2
  125. package/agent-docs/author/frontmatter-reference.sections/feature-availability.md +59 -0
  126. package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +2 -2
  127. package/agent-docs/author/frontmatter-reference.sections/html-markdown-and-agents.md +3 -3
  128. package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +2 -2
  129. package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +2 -2
  130. package/agent-docs/author/frontmatter-reference.sections/product-publication-fields.md +37 -0
  131. package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +2 -2
  132. package/agent-docs/author/frontmatter-reference.sections/related-reading.md +2 -2
  133. package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +4 -4
  134. package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +2 -2
  135. package/agent-docs/author/frontmatter.md +13 -13
  136. package/agent-docs/author/frontmatter.sections/audience-badges.md +3 -3
  137. package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +4 -4
  138. package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +1 -1
  139. package/agent-docs/author/frontmatter.sections/optional-native-fields.md +4 -4
  140. package/agent-docs/author/frontmatter.sections/publication-fields.md +2 -2
  141. package/agent-docs/author/frontmatter.sections/publishing-policy.md +1 -1
  142. package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +1 -1
  143. package/agent-docs/author/frontmatter.sections/related-reading.md +1 -1
  144. package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +1 -1
  145. package/agent-docs/author/frontmatter.sections/seo-fields.md +2 -2
  146. package/agent-docs/author/frontmatter.sections/validation-rules.md +3 -3
  147. package/agent-docs/author/markdown-metadata.md +20 -20
  148. package/agent-docs/author/navigation.md +12 -12
  149. package/agent-docs/author/navigation.sections/arrange-authored-pages.md +4 -4
  150. package/agent-docs/author/navigation.sections/fill-an-api-tag-group.md +2 -2
  151. package/agent-docs/author/navigation.sections/hide-group-page-counts.md +4 -4
  152. package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +4 -4
  153. package/agent-docs/author/navigation.sections/local-api-preview.md +2 -2
  154. package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +3 -3
  155. package/agent-docs/author/navigation.sections/optionally-split-a-large-menu-into-files.md +2 -2
  156. package/agent-docs/author/navigation.sections/reach-navigation-while-reading.md +2 -2
  157. package/agent-docs/author/navigation.sections/related-reading.md +2 -2
  158. package/agent-docs/author/navigation.sections/split-navigation-into-tabs.md +4 -4
  159. package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +3 -3
  160. package/agent-docs/author/reader-views.md +9 -9
  161. package/agent-docs/author/reader-views.sections/configure-the-choices.md +2 -2
  162. package/agent-docs/author/reader-views.sections/connect-your-own-control.md +1 -1
  163. package/agent-docs/author/reader-views.sections/how-it-works-for-agents.md +3 -3
  164. package/agent-docs/author/reader-views.sections/mark-pages.md +3 -3
  165. package/agent-docs/author/reader-views.sections/mark-sections-and-add-an-entry-choice.md +2 -2
  166. package/agent-docs/author/reader-views.sections/place-filter-controls.md +2 -2
  167. package/agent-docs/author/reader-views.sections/try-the-controls-here.md +2 -2
  168. package/agent-docs/author/recipe-drafts.md +5 -5
  169. package/agent-docs/author/recipe-drafts.sections/1-write-one-reusable-step.md +2 -2
  170. package/agent-docs/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md +2 -2
  171. package/agent-docs/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md +1 -1
  172. package/agent-docs/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md +2 -2
  173. package/agent-docs/author/recipe-drafts.sections/related-reading.md +1 -1
  174. package/agent-docs/author/recipe-drafts.sections/start-an-ingredient-from-an-api-example.md +2 -2
  175. package/agent-docs/author/recipes.md +7 -7
  176. package/agent-docs/author/recipes.sections/how-agents-use-this.md +2 -2
  177. package/agent-docs/author/recipes.sections/one-example-from-shoalrun.md +2 -2
  178. package/agent-docs/author/recipes.sections/related-reading.md +1 -1
  179. package/agent-docs/author/recipes.sections/try-a-complete-workflow.md +1 -1
  180. package/agent-docs/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md +3 -3
  181. package/agent-docs/author/recipes.sections/what-changing-an-ingredient-updates.md +2 -2
  182. package/agent-docs/author/recipes.sections/what-each-file-does.md +1 -1
  183. package/agent-docs/author/recipes.sections/what-happens-and-when.md +2 -2
  184. package/agent-docs/author/related-reading.md +11 -11
  185. package/agent-docs/author/related-reading.sections/automatic-footers.md +3 -3
  186. package/agent-docs/author/related-reading.sections/declare-relationships.md +3 -3
  187. package/agent-docs/author/related-reading.sections/display-related-documents.md +3 -3
  188. package/agent-docs/author/related-reading.sections/html-markdown-and-agents.md +1 -1
  189. package/agent-docs/author/related-reading.sections/inspect-output-and-changes.md +2 -2
  190. package/agent-docs/author/related-reading.sections/reading-paths-in-section-markdown.md +3 -3
  191. package/agent-docs/author/related-reading.sections/related-reading.md +1 -1
  192. package/agent-docs/author/related-reading.sections/where-relationship-explanations-come-from.md +2 -2
  193. package/agent-docs/author/release-notes.md +8 -8
  194. package/agent-docs/author/search.md +43 -39
  195. package/agent-docs/author/search.sections/agent-and-mcp-search-scope.md +12 -8
  196. package/agent-docs/author/search.sections/choose-a-provider.md +8 -8
  197. package/agent-docs/author/search.sections/cli-and-mcp-ranking-details.md +4 -4
  198. package/agent-docs/author/search.sections/enable-included-semantic-search.md +5 -5
  199. package/agent-docs/author/search.sections/hosted-semantic-search-limits.md +3 -3
  200. package/agent-docs/author/search.sections/html-markdown-and-agents.md +3 -3
  201. package/agent-docs/author/search.sections/lexical-search.md +6 -6
  202. package/agent-docs/author/search.sections/local-semantic-preview.md +3 -3
  203. package/agent-docs/author/search.sections/read-a-search-result-with-an-agent.md +2 -2
  204. package/agent-docs/author/search.sections/related-reading.md +2 -2
  205. package/agent-docs/author/search.sections/reuse-the-lexical-index.md +5 -5
  206. package/agent-docs/author/search.sections/turn-search-off.md +3 -3
  207. package/agent-docs/author/search.sections/use-the-search-box.md +2 -2
  208. package/agent-docs/author/search.sections/write-a-custom-provider.md +11 -11
  209. package/agent-docs/author/snippets.md +3 -3
  210. package/agent-docs/author/taxonomy.md +3 -3
  211. package/agent-docs/author/templates.md +16 -14
  212. package/agent-docs/author/templates.sections/built-in-feature-templates.md +2 -2
  213. package/agent-docs/author/templates.sections/built-in-templates.md +2 -2
  214. package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +7 -7
  215. package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +8 -6
  216. package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +2 -2
  217. package/agent-docs/author/templates.sections/project-added-templates.md +3 -3
  218. package/agent-docs/author/templates.sections/related-reading.md +2 -2
  219. package/agent-docs/author/templates.sections/scaffold-a-page.md +2 -2
  220. package/agent-docs/author/templates.sections/short-cli-and-derived-values.md +3 -3
  221. package/agent-docs/author/templates.sections/what-every-template-gives-you.md +3 -3
  222. package/agent-docs/author/workspace/commands.md +4 -4
  223. package/agent-docs/author/workspace.md +7 -7
  224. package/agent-docs/author/writing-style.md +33 -18
  225. package/agent-docs/author/writing-style.sections/adapt-this-example.md +2 -2
  226. package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +3 -3
  227. package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +4 -4
  228. package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +2 -2
  229. package/agent-docs/author/writing-style.sections/feature-availability.md +20 -7
  230. package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +5 -5
  231. package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +4 -4
  232. package/agent-docs/author/writing-style.sections/procedures-and-examples.md +4 -4
  233. package/agent-docs/author/writing-style.sections/related-reading.md +2 -2
  234. package/agent-docs/author/writing-style.sections/review-a-draft.md +3 -3
  235. package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +2 -2
  236. package/agent-docs/author/writing-style.sections/voice-and-explanations.md +4 -2
  237. package/agent-docs/changelog/2026-10-14-agent-readiness.md +2 -2
  238. package/agent-docs/changelog/2026-10-15-evaluation-builds.md +9 -9
  239. package/agent-docs/changelog/2026-10-16-navigation-layouts.md +4 -4
  240. package/agent-docs/changelog/2026-10-17-mcp-hosting.md +2 -2
  241. package/agent-docs/changelog/2026-10-18-search-and-tooltips.md +3 -3
  242. package/agent-docs/changelog/2026-10-19-visual-navigation.md +3 -3
  243. package/agent-docs/changelog/2026-10-25.md +2 -2
  244. package/agent-docs/changelog/2026-10-26.md +4 -4
  245. package/agent-docs/changelog/2026-10-27.md +1 -1
  246. package/agent-docs/changelog/2026-10-28.md +3 -3
  247. package/agent-docs/changelog/2026-10-30.md +1 -1
  248. package/agent-docs/changelog/2026-11-03.md +5 -5
  249. package/agent-docs/changelog/2026-11-04-runtime-packaging.md +46 -0
  250. package/agent-docs/changelog/authoring-preview.md +3 -3
  251. package/agent-docs/changelog/authoring-search.md +1 -1
  252. package/agent-docs/changelog/authoring-tools.md +2 -2
  253. package/agent-docs/changelog/branding-security.md +66 -0
  254. package/agent-docs/changelog/product-publications.md +60 -0
  255. package/agent-docs/changelog/working-tree-skill.md +1 -1
  256. package/agent-docs/changelog.md +25 -1
  257. package/agent-docs/chat/checks.md +11 -11
  258. package/agent-docs/chat/checks.sections/answer-ahead-of-time.md +1 -1
  259. package/agent-docs/chat/checks.sections/answer-for-one-audience.md +2 -2
  260. package/agent-docs/chat/checks.sections/answer-without-a-model.md +2 -2
  261. package/agent-docs/chat/checks.sections/follow-up-questions.md +2 -2
  262. package/agent-docs/chat/checks.sections/how-an-answer-is-checked.md +3 -3
  263. package/agent-docs/chat/checks.sections/questions-with-several-parts.md +3 -3
  264. package/agent-docs/chat/checks.sections/related-reading.md +1 -1
  265. package/agent-docs/chat/checks.sections/reuse-answers.md +4 -4
  266. package/agent-docs/chat/host.md +28 -10
  267. package/agent-docs/chat/host.sections/cap-the-daily-spend.md +2 -2
  268. package/agent-docs/chat/host.sections/keep-a-record-of-questions.md +3 -3
  269. package/agent-docs/chat/host.sections/related-reading.md +2 -2
  270. package/agent-docs/chat/passage-index.md +17 -17
  271. package/agent-docs/chat/passage-index.sections/build-the-index.md +2 -2
  272. package/agent-docs/chat/passage-index.sections/embed-passages.md +3 -3
  273. package/agent-docs/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md +2 -2
  274. package/agent-docs/chat/passage-index.sections/limits.md +2 -2
  275. package/agent-docs/chat/passage-index.sections/passage-ids-and-links.md +3 -3
  276. package/agent-docs/chat/passage-index.sections/related-reading.md +2 -2
  277. package/agent-docs/chat/passage-index.sections/what-a-passage-contains.md +15 -15
  278. package/agent-docs/chat/prepared-answers.md +4 -4
  279. package/agent-docs/chat/settings.md +4 -4
  280. package/agent-docs/chat/settings.sections/choose-the-scorer.md +1 -1
  281. package/agent-docs/chat/settings.sections/configure-chat.md +2 -2
  282. package/agent-docs/chat/settings.sections/configure-retrieval.md +1 -1
  283. package/agent-docs/chat/settings.sections/related-reading.md +1 -1
  284. package/agent-docs/chat/settings.sections/send-extra-request-fields.md +2 -2
  285. package/agent-docs/chat/settings.sections/use-more-than-one-model.md +2 -2
  286. package/agent-docs/chat/settings.sections/when-the-scorer-is-down.md +1 -1
  287. package/agent-docs/chat/setup.md +2 -2
  288. package/agent-docs/chat.md +3 -3
  289. package/agent-docs/cli.md +73 -59
  290. package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +11 -7
  291. package/agent-docs/cli.sections/author-pages.md +16 -12
  292. package/agent-docs/cli.sections/build-and-serve.md +30 -18
  293. package/agent-docs/cli.sections/inspect-config-and-operations.md +13 -9
  294. package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +7 -3
  295. package/agent-docs/cli.sections/related-reading.md +6 -2
  296. package/agent-docs/cli.sections/search-and-chat.md +24 -18
  297. package/agent-docs/cli.sections/start-a-project.md +7 -3
  298. package/agent-docs/cli.sections/working-tree-authoring-tools.md +7 -3
  299. package/agent-docs/concepts.md +2 -2
  300. package/agent-docs/config/apis.md +2 -2
  301. package/agent-docs/config/content.md +3 -3
  302. package/agent-docs/config/content.sections/authoring.md +3 -3
  303. package/agent-docs/config/content.sections/badges.md +1 -1
  304. package/agent-docs/config/content.sections/callouts.md +1 -1
  305. package/agent-docs/config/content.sections/cookbooks.md +1 -1
  306. package/agent-docs/config/content.sections/frontmatter.md +1 -1
  307. package/agent-docs/config/content.sections/readerfilters.md +1 -1
  308. package/agent-docs/config/content.sections/related-reading.md +1 -1
  309. package/agent-docs/config/content.sections/relationships.md +1 -1
  310. package/agent-docs/config/content.sections/snippets.md +1 -1
  311. package/agent-docs/config/content.sections/templates.md +1 -1
  312. package/agent-docs/config/content.sections/variables.md +1 -1
  313. package/agent-docs/config/examples.md +4 -4
  314. package/agent-docs/config/examples.sections/feature-showcase.md +4 -4
  315. package/agent-docs/config/examples.sections/minimal-site.md +2 -2
  316. package/agent-docs/config/examples.sections/multilingual-help-center.md +2 -2
  317. package/agent-docs/config/examples.sections/parcel-api-documentation.md +2 -2
  318. package/agent-docs/config/examples.sections/related-reading.md +2 -2
  319. package/agent-docs/config/examples.sections/shared-company-preset.md +2 -2
  320. package/agent-docs/config/integrations.md +4 -4
  321. package/agent-docs/config/outputs.md +22 -16
  322. package/agent-docs/config/outputs.sections/exports.md +19 -13
  323. package/agent-docs/config/outputs.sections/metadata.md +2 -2
  324. package/agent-docs/config/outputs.sections/related-reading.md +1 -1
  325. package/agent-docs/config/publishing.md +29 -19
  326. package/agent-docs/config/publishing.sections/navigation.md +2 -2
  327. package/agent-docs/config/publishing.sections/redirects.md +8 -8
  328. package/agent-docs/config/publishing.sections/related-reading.md +2 -2
  329. package/agent-docs/config/site.md +42 -18
  330. package/agent-docs/config/site.sections/related-reading.md +1 -1
  331. package/agent-docs/config/site.sections/theme.md +1 -1
  332. package/agent-docs/config.md +2 -2
  333. package/agent-docs/configuration.md +19 -19
  334. package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +1 -1
  335. package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +5 -5
  336. package/agent-docs/configuration.sections/extract-a-section-with-include.md +1 -1
  337. package/agent-docs/configuration.sections/inspect-and-validate-changes.md +5 -5
  338. package/agent-docs/configuration.sections/related-reading.md +1 -1
  339. package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +5 -5
  340. package/agent-docs/configuration.sections/share-defaults-through-extends.md +3 -3
  341. package/agent-docs/configuration.sections/start-with-one-working-file.md +2 -2
  342. package/agent-docs/configuration.sections/understand-the-three-stages.md +3 -3
  343. package/agent-docs/configuration.sections/understand-where-paths-point.md +2 -2
  344. package/agent-docs/connect/mcp.md +24 -15
  345. package/agent-docs/content-delivery/agents.md +6 -6
  346. package/agent-docs/content-delivery/api.md +29 -16
  347. package/agent-docs/content-delivery/client.md +14 -8
  348. package/agent-docs/content-delivery/http-api/operations/get-content-representation-fa1d2e3f.md +10 -2
  349. package/agent-docs/content-delivery/http-api/operations/get-content-representation-head-4052375c.md +10 -2
  350. package/agent-docs/content-delivery/http-api/operations/get-content-resource-849f1c49.md +537 -3
  351. package/agent-docs/content-delivery/http-api/operations/get-content-resource-head-0a352acd.md +10 -2
  352. package/agent-docs/content-delivery/http-api/operations/list-content-resources-8e977ec7.md +545 -3
  353. package/agent-docs/content-delivery/http-api/operations/list-content-resources-head-b67cbad9.md +10 -2
  354. package/agent-docs/content-delivery/http-api.md +21 -7
  355. package/agent-docs/content-delivery/manifest.md +30 -8
  356. package/agent-docs/content-delivery/publish.md +5 -5
  357. package/agent-docs/content-delivery/render.md +6 -6
  358. package/agent-docs/content-delivery/rest.md +16 -8
  359. package/agent-docs/content-delivery/sections.md +11 -11
  360. package/agent-docs/content-delivery/select.md +6 -6
  361. package/agent-docs/content-delivery.md +4 -4
  362. package/agent-docs/contribute/agent-skills.md +3 -3
  363. package/agent-docs/cookbooks/authoring.md +3 -3
  364. package/agent-docs/cookbooks/site-workflows.md +2 -2
  365. package/agent-docs/cookbooks/welcome-email.md +3 -3
  366. package/agent-docs/documents.json +2500 -1927
  367. package/agent-docs/example-api/cedar.md +4 -4
  368. package/agent-docs/features.md +49 -0
  369. package/agent-docs/glossary.md +22 -22
  370. package/agent-docs/index.md +5 -5
  371. package/agent-docs/ingredients/audit-site.md +2 -2
  372. package/agent-docs/ingredients/build-site.md +2 -2
  373. package/agent-docs/ingredients/complete-page.md +2 -2
  374. package/agent-docs/ingredients/refresh-agent-bundle.md +2 -2
  375. package/agent-docs/non-goals.md +4 -4
  376. package/agent-docs/provenance.json +10 -4
  377. package/agent-docs/publish/agent-discovery.md +8 -2
  378. package/agent-docs/publish/agent-friendliness.md +21 -21
  379. package/agent-docs/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md +5 -5
  380. package/agent-docs/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md +5 -5
  381. package/agent-docs/publish/agent-friendliness.sections/evidence-has-a-scope.md +5 -5
  382. package/agent-docs/publish/agent-friendliness.sections/keep-shared-instructions-complete.md +5 -5
  383. package/agent-docs/publish/agent-friendliness.sections/related-reading.md +3 -3
  384. package/agent-docs/publish/agent-friendliness.sections/secret-handshake.md +3 -3
  385. package/agent-docs/publish/agent-friendliness.sections/try-the-page-controls.md +3 -3
  386. package/agent-docs/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md +4 -4
  387. package/agent-docs/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md +9 -9
  388. package/agent-docs/publish/agent-friendliness.sections/what-an-agent-reads.md +5 -5
  389. package/agent-docs/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md +4 -4
  390. package/agent-docs/publish/api-references.md +5 -5
  391. package/agent-docs/publish/api-references.sections/author-the-reference-page.md +2 -2
  392. package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +3 -3
  393. package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +2 -2
  394. package/agent-docs/publish/api-references.sections/next-steps.md +2 -2
  395. package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +2 -2
  396. package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +2 -2
  397. package/agent-docs/publish/api-references.sections/register-the-operation.md +2 -2
  398. package/agent-docs/publish/api-references.sections/related-reading.md +2 -2
  399. package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +3 -3
  400. package/agent-docs/publish/api-references.sections/what-readers-get.md +3 -3
  401. package/agent-docs/publish/audit.md +8 -8
  402. package/agent-docs/publish/audit.sections/add-project-tests.md +2 -2
  403. package/agent-docs/publish/audit.sections/check-agent-evaluation-reports.md +2 -2
  404. package/agent-docs/publish/audit.sections/check-before-pushing.md +3 -3
  405. package/agent-docs/publish/audit.sections/connect-a-documentation-test-suite.md +2 -2
  406. package/agent-docs/publish/audit.sections/read-the-report.md +3 -3
  407. package/agent-docs/publish/audit.sections/related-reading.md +1 -1
  408. package/agent-docs/publish/content-export.md +37 -15
  409. package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +4 -4
  410. package/agent-docs/publish/content-export.sections/check-the-result.md +2 -2
  411. package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +3 -3
  412. package/agent-docs/publish/content-export.sections/prerequisites.md +4 -4
  413. package/agent-docs/publish/content-export.sections/related-reading.md +2 -2
  414. package/agent-docs/publish/content-export.sections/review-exported-api-material.md +3 -3
  415. package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +2 -2
  416. package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +4 -4
  417. package/agent-docs/publish/content-negotiation.md +10 -10
  418. package/agent-docs/publish/content-negotiation.sections/hosting-contract.md +2 -2
  419. package/agent-docs/publish/content-negotiation.sections/missing-pages.md +3 -3
  420. package/agent-docs/publish/content-negotiation.sections/related-reading.md +1 -1
  421. package/agent-docs/publish/content-negotiation.sections/validators-and-manifest-links.md +2 -2
  422. package/agent-docs/publish/content-negotiation.sections/verify-the-deployed-url.md +2 -2
  423. package/agent-docs/publish/content-negotiation.sections/what-if-the-host-cannot-negotiate.md +3 -3
  424. package/agent-docs/publish/content-negotiation.sections/what-shoalrun-builds-and-what-the-host-does.md +2 -2
  425. package/agent-docs/publish/content-negotiation.sections/why-this-matters.md +2 -2
  426. package/agent-docs/publish/deployment-check.md +6 -6
  427. package/agent-docs/publish/deployment-profiles.md +60 -26
  428. package/agent-docs/publish/deployment-profiles.sections/before-you-begin.md +5 -5
  429. package/agent-docs/publish/deployment-profiles.sections/build-and-inspect-the-edition.md +9 -9
  430. package/agent-docs/publish/deployment-profiles.sections/check-the-result.md +7 -7
  431. package/agent-docs/publish/deployment-profiles.sections/choose-navigation-labels.md +6 -6
  432. package/agent-docs/publish/deployment-profiles.sections/current-limits.md +7 -7
  433. package/agent-docs/publish/deployment-profiles.sections/define-the-shared-sku-manifest.md +6 -6
  434. package/agent-docs/publish/deployment-profiles.sections/html-markdown-and-agents.md +7 -7
  435. package/agent-docs/publish/deployment-profiles.sections/mark-pages-and-shared-sections.md +13 -13
  436. package/agent-docs/publish/deployment-profiles.sections/preview-and-edit-a-customer-edition.md +55 -0
  437. package/agent-docs/publish/deployment-profiles.sections/related-reading.md +6 -6
  438. package/agent-docs/publish/deployment-profiles.sections/select-each-product-release.md +55 -0
  439. package/agent-docs/publish/deployment-profiles.sections/supply-the-profile-from-the-deployment.md +6 -6
  440. package/agent-docs/publish/evals.md +16 -16
  441. package/agent-docs/publish/evals.sections/add-the-audit-hook.md +5 -5
  442. package/agent-docs/publish/evals.sections/check-the-report.md +4 -4
  443. package/agent-docs/publish/evals.sections/define-a-task-file.md +5 -5
  444. package/agent-docs/publish/evals.sections/diagnose-a-different-build.md +5 -5
  445. package/agent-docs/publish/evals.sections/prepare-a-report-for-the-built-site.md +5 -5
  446. package/agent-docs/publish/evals.sections/related-reading.md +3 -3
  447. package/agent-docs/publish/evals.sections/run-and-review-the-tasks.md +4 -4
  448. package/agent-docs/publish/evals.sections/shoalrun-s-own-example.md +6 -6
  449. package/agent-docs/publish/host-adapters.md +6 -6
  450. package/agent-docs/publish/manni.md +16 -16
  451. package/agent-docs/publish/manni.sections/check-the-result.md +3 -3
  452. package/agent-docs/publish/manni.sections/how-this-site-uses-manni.md +6 -6
  453. package/agent-docs/publish/manni.sections/optional-custom-policies.md +4 -4
  454. package/agent-docs/publish/manni.sections/prerequisites.md +2 -2
  455. package/agent-docs/publish/mcp-analytics.md +12 -12
  456. package/agent-docs/publish/mcp-analytics.sections/adapter-exports.md +4 -4
  457. package/agent-docs/publish/mcp-analytics.sections/enable-analytics.md +4 -4
  458. package/agent-docs/publish/mcp-analytics.sections/event-fields-and-service-mappings.md +4 -4
  459. package/agent-docs/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md +4 -4
  460. package/agent-docs/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md +5 -5
  461. package/agent-docs/publish/mcp-analytics.sections/related-reading.md +3 -3
  462. package/agent-docs/publish/mcp-analytics.sections/safeguards-and-limits.md +5 -5
  463. package/agent-docs/publish/mcp.md +56 -29
  464. package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +8 -8
  465. package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +4 -4
  466. package/agent-docs/publish/mcp.sections/configure-the-client.md +4 -4
  467. package/agent-docs/publish/mcp.sections/discover-product-releases-before-searching.md +52 -0
  468. package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +6 -6
  469. package/agent-docs/publish/mcp.sections/html-markdown-and-agents.md +38 -0
  470. package/agent-docs/publish/mcp.sections/related-reading.md +3 -3
  471. package/agent-docs/publish/mcp.sections/search-then-read.md +13 -12
  472. package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +12 -8
  473. package/agent-docs/publish/mcp.sections/verify-the-connection.md +4 -4
  474. package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +4 -4
  475. package/agent-docs/publish/openapi-extension-mappings.md +12 -12
  476. package/agent-docs/publish/output.md +20 -20
  477. package/agent-docs/publish/output.sections/api-contracts.md +1 -1
  478. package/agent-docs/publish/output.sections/code-highlighting.md +1 -1
  479. package/agent-docs/publish/output.sections/current-limits.md +1 -1
  480. package/agent-docs/publish/output.sections/incremental-sync.md +4 -4
  481. package/agent-docs/publish/output.sections/manifest-records-and-sections.md +3 -3
  482. package/agent-docs/publish/output.sections/navigation-section-indexes.md +1 -1
  483. package/agent-docs/publish/output.sections/page-formats.md +2 -2
  484. package/agent-docs/publish/output.sections/published-output-contract.md +5 -5
  485. package/agent-docs/publish/output.sections/reader-appearance-and-controls.md +1 -1
  486. package/agent-docs/publish/output.sections/related-reading.md +1 -1
  487. package/agent-docs/publish/output.sections/response-identity.md +1 -1
  488. package/agent-docs/publish/output.sections/site-files.md +6 -6
  489. package/agent-docs/publish/output.sections/validate-an-existing-build-locally.md +3 -3
  490. package/agent-docs/publish/output.sections/where-files-go.md +3 -3
  491. package/agent-docs/publish/publications.md +108 -19
  492. package/agent-docs/publish/publications.sections/add-a-language.md +60 -0
  493. package/agent-docs/publish/publications.sections/change-just-one-part-of-a-shared-page.md +63 -0
  494. package/agent-docs/publish/publications.sections/give-each-api-version-its-own-contract.md +34 -0
  495. package/agent-docs/publish/publications.sections/keep-an-unchanged-page-in-one-file.md +53 -0
  496. package/agent-docs/publish/publications.sections/publish-versions-without-a-product-catalog.md +49 -0
  497. package/agent-docs/publish/publications.sections/related-reading.md +42 -0
  498. package/agent-docs/publish/publications.sections/version-products-independently.md +115 -0
  499. package/agent-docs/publish/publications.sections/what-agents-receive.md +38 -0
  500. package/agent-docs/publish/revisions.md +4 -4
  501. package/agent-docs/publish/seo.md +10 -10
  502. package/agent-docs/publish/seo.sections/related-reading.md +2 -2
  503. package/agent-docs/publish/seo.sections/set-the-public-address.md +3 -3
  504. package/agent-docs/publish/seo.sections/what-agents-receive.md +3 -3
  505. package/agent-docs/publish/seo.sections/what-the-build-adds.md +2 -2
  506. package/agent-docs/publish/seo.sections/write-the-page-title-and-summary.md +2 -2
  507. package/agent-docs/publish/single-source-sites.md +5 -5
  508. package/agent-docs/publish/troubleshooting.md +10 -10
  509. package/agent-docs/publish/vercel.md +5 -5
  510. package/agent-docs/publish/vercel.sections/check-the-deployment.md +1 -1
  511. package/agent-docs/publish/vercel.sections/include-an-mcp-endpoint.md +2 -2
  512. package/agent-docs/publish/vercel.sections/prepare-your-project.md +2 -2
  513. package/agent-docs/publish/vercel.sections/related-reading.md +1 -1
  514. package/agent-docs/publish.md +2 -2
  515. package/agent-docs/recipes/add-page.md +5 -5
  516. package/agent-docs/recipes/add-page.sections/audit-the-shoalrun-docs-project.md +2 -2
  517. package/agent-docs/recipes/add-page.sections/before-you-start.md +1 -1
  518. package/agent-docs/recipes/add-page.sections/build-the-shoalrun-docs-site.md +2 -2
  519. package/agent-docs/recipes/add-page.sections/check-agent-search-and-page-lookup.md +1 -1
  520. package/agent-docs/recipes/add-page.sections/check-the-built-page-artifacts.md +1 -1
  521. package/agent-docs/recipes/add-page.sections/check-the-outcome.md +1 -1
  522. package/agent-docs/recipes/add-page.sections/complete-the-guide-and-add-navigation.md +2 -2
  523. package/agent-docs/recipes/add-page.sections/install-the-site-dependencies.md +1 -1
  524. package/agent-docs/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md +2 -2
  525. package/agent-docs/recipes/add-page.sections/related-reading.md +1 -1
  526. package/agent-docs/recipes/add-page.sections/scaffold-a-new-guide.md +1 -1
  527. package/agent-docs/recipes/audit-docs.md +4 -4
  528. package/agent-docs/recipes/build-docs.md +2 -2
  529. package/agent-docs/recipes/preview-hybrid-search.md +5 -5
  530. package/agent-docs/recipes/preview-page.md +2 -2
  531. package/agent-docs/recipes/queue-email.md +2 -2
  532. package/agent-docs/recipes/refresh-agent-docs.md +4 -4
  533. package/agent-docs/recipes/send-welcome-email.md +13 -13
  534. package/agent-docs/reference/agent-skills.md +7 -7
  535. package/agent-docs/search-and-chat.md +4 -4
  536. package/agent-docs/search-index.json +1 -1
  537. package/agent-docs/start.md +5 -5
  538. package/agent-docs/start.sections/add-the-page-to-navigation.md +3 -3
  539. package/agent-docs/start.sections/build-and-check-both-outputs.md +3 -3
  540. package/agent-docs/start.sections/build-this-site.md +2 -2
  541. package/agent-docs/start.sections/check-writing-style.md +2 -2
  542. package/agent-docs/start.sections/create-a-page.md +2 -2
  543. package/agent-docs/start.sections/make-it-yours.md +2 -2
  544. package/agent-docs/start.sections/migrating-from-github-packages.md +2 -2
  545. package/agent-docs/start.sections/prerequisites.md +2 -2
  546. package/agent-docs/start.sections/related-reading.md +2 -2
  547. package/agent-docs/start.sections/start-your-own-project.md +3 -3
  548. package/agent-docs/status.md +14 -4
  549. package/agent-docs/styling/color-modes.md +2 -2
  550. package/agent-docs/styling/footer.md +2 -2
  551. package/agent-docs/styling/header.md +2 -2
  552. package/agent-docs/styling/layouts.md +3 -3
  553. package/agent-docs/styling/layouts.sections/build-a-landing-page.md +1 -1
  554. package/agent-docs/styling/layouts.sections/build-a-splash-page.md +1 -1
  555. package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +2 -2
  556. package/agent-docs/styling/layouts.sections/customize-the-hero.md +1 -1
  557. package/agent-docs/styling/layouts.sections/hero.md +1 -1
  558. package/agent-docs/styling/layouts.sections/hide-the-table-of-contents-or-give-content-more-room.md +1 -1
  559. package/agent-docs/styling/layouts.sections/html-markdown-and-agents.md +2 -2
  560. package/agent-docs/styling/layouts.sections/related-reading.md +1 -1
  561. package/agent-docs/styling/palettes.md +3 -3
  562. package/agent-docs/styling/share-images.md +3 -3
  563. package/agent-docs/styling/themes.md +2 -2
  564. package/agent-docs/styling/try.md +2 -2
  565. package/agent-docs/what-is-shoalrun.md +7 -3
  566. package/assets/ask-widget.js +21 -7
  567. package/assets/navigation.js +5 -0
  568. package/dist/api-materialize.d.ts +2 -1
  569. package/dist/api-materialize.js +21 -9
  570. package/dist/api-publication-plan.d.ts +2 -0
  571. package/dist/api-publication-plan.js +23 -7
  572. package/dist/api-publication-review.js +4 -3
  573. package/dist/api-selection.d.ts +5 -2
  574. package/dist/api-selection.js +18 -11
  575. package/dist/artifact-bundle.js +9 -6
  576. package/dist/ask-function.js +5 -2
  577. package/dist/ask-runtime.d.ts +1 -0
  578. package/dist/ask-runtime.js +7 -2
  579. package/dist/authored-change.js +2 -1
  580. package/dist/authoring-project.js +1 -1
  581. package/dist/cards.js +2 -1
  582. package/dist/chat-config.d.ts +2 -0
  583. package/dist/chat-config.js +10 -2
  584. package/dist/cli-discovery.d.ts +2 -2
  585. package/dist/cli-discovery.js +9 -4
  586. package/dist/cli.js +50 -25
  587. package/dist/compiler-config.d.ts +17 -0
  588. package/dist/compiler-config.js +43 -2
  589. package/dist/compiler.d.ts +21 -0
  590. package/dist/compiler.js +16 -12
  591. package/dist/component-transform.d.ts +2 -4
  592. package/dist/component-transform.js +20 -7
  593. package/dist/config.d.ts +1 -0
  594. package/dist/config.js +2 -1
  595. package/dist/content-delivery-contract.d.ts +2 -1
  596. package/dist/content-delivery-validation.d.ts +2 -2
  597. package/dist/content-delivery-validation.js +6 -4
  598. package/dist/content-export-command.d.ts +1 -1
  599. package/dist/content-export-command.js +4 -4
  600. package/dist/content-export-comparison.js +6 -5
  601. package/dist/content-export-config.js +3 -1
  602. package/dist/content-export.js +9 -8
  603. package/dist/content-rest-client.js +4 -2
  604. package/dist/content-rest-contract.d.ts +2 -2
  605. package/dist/content-rest-server.js +11 -6
  606. package/dist/content-source.d.ts +13 -0
  607. package/dist/content-source.js +5 -2
  608. package/dist/content-workspace.d.ts +12 -0
  609. package/dist/content-workspace.js +2 -1
  610. package/dist/content.js +3 -2
  611. package/dist/cookbook-chooser.js +2 -1
  612. package/dist/deployment-profile.d.ts +2 -1
  613. package/dist/deployment-profile.js +38 -8
  614. package/dist/dev.d.ts +3 -1
  615. package/dist/dev.js +99 -12
  616. package/dist/docs-author.js +2 -1
  617. package/dist/docs-command.js +2 -2
  618. package/dist/docs-eval.d.ts +1 -0
  619. package/dist/docs-eval.js +2 -2
  620. package/dist/docs-mcp.d.ts +1 -0
  621. package/dist/docs-mcp.js +10 -5
  622. package/dist/docs-tool.d.ts +4 -10
  623. package/dist/document-sync.d.ts +1 -0
  624. package/dist/document-sync.js +2 -2
  625. package/dist/documentation-core.d.ts +29 -10
  626. package/dist/documentation-core.js +38 -4
  627. package/dist/freshness.js +2 -2
  628. package/dist/frontmatter.js +13 -7
  629. package/dist/function-runtime.d.ts +1 -0
  630. package/dist/index-build.d.ts +1 -0
  631. package/dist/index-build.js +2 -2
  632. package/dist/ingredient-draft.js +20 -10
  633. package/dist/mcp-analytics.d.ts +1 -0
  634. package/dist/mcp-artifacts.js +13 -4
  635. package/dist/mcp-config.d.ts +1 -0
  636. package/dist/mcp-config.js +3 -1
  637. package/dist/mcp-http.js +1 -1
  638. package/dist/page-materialization.d.ts +3 -4
  639. package/dist/page-materialization.js +15 -8
  640. package/dist/page-renderer.d.ts +6 -0
  641. package/dist/page-renderer.js +16 -5
  642. package/dist/project-navigation.js +2 -1
  643. package/dist/publication-identity.d.ts +12 -0
  644. package/dist/publication-identity.js +17 -0
  645. package/dist/publication-manifest.d.ts +24 -1
  646. package/dist/publication-manifest.js +14 -6
  647. package/dist/publication-plan.js +21 -9
  648. package/dist/publication-render.js +24 -8
  649. package/dist/recipe-draft.js +9 -6
  650. package/dist/scaffold.d.ts +7 -4
  651. package/dist/scaffold.js +16 -16
  652. package/dist/search-query.d.ts +4 -10
  653. package/dist/search-query.js +10 -9
  654. package/dist/server.d.ts +8 -0
  655. package/dist/server.js +14 -3
  656. package/dist/subject-deprecation.js +2 -1
  657. package/dist/turnstile-policy.d.ts +2 -0
  658. package/dist/turnstile-policy.js +23 -0
  659. package/dist/turnstile.d.ts +7 -0
  660. package/dist/turnstile.js +29 -2
  661. package/dist/vercel-function.js +2 -2
  662. package/example-configs/products/README.md +37 -0
  663. package/example-configs/products/content/operations.mdx +50 -0
  664. package/example-configs/products/content/payments-v2.mdx +30 -0
  665. package/example-configs/products/content/payments-v3.mdx +38 -0
  666. package/example-configs/products/content/priority-settlement.mdx +23 -0
  667. package/example-configs/products/content/reporting-v1.mdx +36 -0
  668. package/example-configs/products/content/scheduled-exports.mdx +23 -0
  669. package/example-configs/products/docs.config.yaml +56 -0
  670. package/example-configs/products/profiles/all-releases.yaml +9 -0
  671. package/example-configs/products/profiles/customer-a.yaml +13 -0
  672. package/example-configs/products/profiles/customer-b.yaml +13 -0
  673. package/example-configs/products/skus.yaml +11 -0
  674. package/examples/content-delivery/preview.mjs +1 -1
  675. package/package.json +1 -1
  676. package/schemas/content-export.schema.json +41 -3
  677. package/schemas/content-rest.openapi.json +184 -37
  678. package/skills/shoalrun-author/SKILL.md +6 -2
  679. package/skills/shoalrun-author/references/customer-editions.md +34 -4
  680. package/skills/shoalrun-author/references/publications.md +60 -0
  681. package/skills/shoalrun-brand/SKILL.md +52 -0
  682. package/skills/shoalrun-recipes/SKILL.md +2 -0
  683. package/skills/shoalrun-setup/SKILL.md +3 -1
  684. package/styles/header.css +3 -0
  685. package/styles/site.css +3 -0
  686. package/agent-docs/publish/content-export.sections/export-selected-pages.md +0 -116
@@ -1,3 +1,4 @@
1
+ import { samePublication } from './publication-identity.js';
1
2
  import { ContentDeliveryError, contentRefKey } from './content-delivery-contract.js';
2
3
  const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
3
4
  const keys = (value, allowed) => object(value) && Object.keys(value).every(key => allowed.includes(key));
@@ -6,8 +7,7 @@ const digestPattern = /^[a-f0-9]{64}$/;
6
7
  const pathPattern = /^(?:NOTICES\.txt|(?:content|assets)\/[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*)$/;
7
8
  export const safeContentPath = (value) => typeof value === 'string' && pathPattern.test(value) && value.split('/').every(part => part !== '.' && part !== '..');
8
9
  const invalid = (message) => { throw new ContentDeliveryError('invalid_manifest', message); };
9
- export const validContentPublication = (value) => object(value) && Object.keys(value).length === 3 && ['channel', 'version', 'language'].every(key => nonempty(value[key]));
10
- const samePublication = (left, right) => ['channel', 'version', 'language'].every(key => left[key] === right[key]);
10
+ export const validContentPublication = (value) => keys(value, ['channel', 'version', 'language', 'product']) && ['channel', 'version', 'language'].every(key => nonempty(value[key])) && (value.product === undefined ? !Object.hasOwn(value, 'product') : nonempty(value.product));
11
11
  export function validContentRef(value) {
12
12
  if (!object(value))
13
13
  return false;
@@ -27,11 +27,11 @@ function safeExternal(value, image = false) {
27
27
  }
28
28
  }
29
29
  export function validateContentManifest(value, maxResources = 10_000, maxResourceBytes = 8_000_000) {
30
- if (!keys(value, ['schemaVersion', 'kind', 'digest', 'publicBase', 'publication', 'review', 'resources', 'assets', 'files', 'diagnostics']) || value.schemaVersion !== 1 || value.kind !== 'shoalrun-content-export' || !digestPattern.test(value.digest ?? ''))
30
+ if (!keys(value, ['schemaVersion', 'kind', 'digest', 'publicBase', 'publication', 'review', 'resources', 'assets', 'files', 'diagnostics']) || ![1, 2].includes(value.schemaVersion) || value.kind !== 'shoalrun-content-export' || !digestPattern.test(value.digest ?? ''))
31
31
  invalid('Unsupported content manifest.');
32
32
  if (typeof value.publicBase !== 'string' || !/^\/(?:[A-Za-z0-9_~.-]+\/)*$/.test(value.publicBase) || value.publicBase.split('/').some((part) => part === '.' || part === '..'))
33
33
  invalid('Invalid content mount.');
34
- if (!validContentPublication(value.publication))
34
+ if (!validContentPublication(value.publication) || value.schemaVersion !== (value.publication.product === undefined ? 1 : 2))
35
35
  invalid('Invalid publication.');
36
36
  if (!keys(value.review, ['status', 'apis']) || value.review.status !== 'ok' || !Array.isArray(value.review.apis) || value.review.apis.some((api) => !keys(api, ['apiId', 'digest']) || !nonempty(api.apiId) || !digestPattern.test(api.digest ?? '')))
37
37
  invalid('Content must have approved API review metadata.');
@@ -57,6 +57,8 @@ export function validateContentManifest(value, maxResources = 10_000, maxResourc
57
57
  }
58
58
  /** Shared metadata validation; transport supplies its file/asset inventory policy. */
59
59
  export function validateContentResources(resources, expectedPublication, assets, checkRepresentation, publicBase = '/') {
60
+ if (!validContentPublication(expectedPublication))
61
+ invalid('Invalid expected publication.');
60
62
  const refs = new Set();
61
63
  const links = [];
62
64
  for (const resource of resources) {
@@ -1,4 +1,4 @@
1
- export declare const exportHelp = "Usage: shoalrun export [config] --out DIRECTORY [--target NAME]\n [--format markdown|html|both] [--document ID]...\n [--channel C --version V --language L] [--public-base /help/] [--review]\n [--profile FILE] [--previous-manifest FILE] [--fail-on-removed]\n\nExport selected pages, sections, and named snippets as Markdown and passive HTML.\nConfigure typed resources in an export target; --document selects whole pages.\nNavigation, facets, and a prior website build are not required.\n--review writes an API-review candidate; status needs-review exits 2 until pinned.\n--previous-manifest compares public references with an earlier reviewed export.\n--fail-on-removed requires that baseline and refuses to replace output if references disappear.\n";
1
+ export declare const exportHelp = "Usage: shoalrun export [config] --out DIRECTORY [--target NAME]\n [--format markdown|html|both] [--document ID]...\n [--channel C --version V --language L [--product P]] [--public-base /help/] [--review]\n [--profile FILE] [--previous-manifest FILE] [--fail-on-removed]\n\nExport selected pages, sections, and named snippets as Markdown and passive HTML.\nConfigure typed resources in an export target; --document selects whole pages.\nNavigation, facets, and a prior website build are not required.\n--review writes an API-review candidate; status needs-review exits 2 until pinned.\n--previous-manifest compares public references with an earlier reviewed export.\n--fail-on-removed requires that baseline and refuses to replace output if references disappear.\n";
2
2
  export declare function runExportCommand(args: string[]): Promise<{
3
3
  status: string;
4
4
  output: string;
@@ -1,7 +1,7 @@
1
1
  import { exportContent } from './content-export.js';
2
2
  export const exportHelp = `Usage: shoalrun export [config] --out DIRECTORY [--target NAME]
3
3
  [--format markdown|html|both] [--document ID]...
4
- [--channel C --version V --language L] [--public-base /help/] [--review]
4
+ [--channel C --version V --language L [--product P]] [--public-base /help/] [--review]
5
5
  [--profile FILE] [--previous-manifest FILE] [--fail-on-removed]
6
6
 
7
7
  Export selected pages, sections, and named snippets as Markdown and passive HTML.
@@ -30,7 +30,7 @@ export async function runExportCommand(args) {
30
30
  continue;
31
31
  }
32
32
  if (arg.startsWith('--')) {
33
- if (!['--out', '--target', '--format', '--document', '--channel', '--version', '--language', '--public-base', '--previous-manifest', '--profile'].includes(arg) || !args[index + 1] || args[index + 1].startsWith('--'))
33
+ if (!['--out', '--target', '--format', '--document', '--channel', '--version', '--language', '--product', '--public-base', '--previous-manifest', '--profile'].includes(arg) || !args[index + 1] || args[index + 1].startsWith('--'))
34
34
  throw new Error(exportHelp);
35
35
  const value = args[++index];
36
36
  if (arg === '--document') {
@@ -56,10 +56,10 @@ export async function runExportCommand(args) {
56
56
  if (format)
57
57
  options.formats = format === 'both' ? ['markdown', 'html'] : [format];
58
58
  const coordinates = ['--channel', '--version', '--language'].map(key => values.get(key));
59
- if (coordinates.some(Boolean)) {
59
+ if (coordinates.some(Boolean) || values.has('--product')) {
60
60
  if (!coordinates.every(Boolean))
61
61
  throw new Error('Select all three export publication coordinates: --channel, --version, and --language');
62
- options.publication = { channel: coordinates[0], version: coordinates[1], language: coordinates[2] };
62
+ options.publication = { channel: coordinates[0], version: coordinates[1], language: coordinates[2], ...(values.has('--product') ? { product: values.get('--product') } : {}) };
63
63
  }
64
64
  options.profile = values.get('--profile');
65
65
  options.target = values.get('--target');
@@ -1,14 +1,15 @@
1
+ import { validContentPublication } from './content-delivery-validation.js';
1
2
  import { contentRefKey } from './content-delivery-contract.js';
2
3
  const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
3
4
  const nonempty = (value) => typeof value === 'string' && value.length > 0 && value.trim() === value;
4
- const keyFor = ({ publication, ref }) => JSON.stringify([publication.channel, publication.version, publication.language, contentRefKey(ref)]);
5
+ const keyFor = ({ publication, ref }) => JSON.stringify([publication.channel, publication.version, publication.language, ...(publication.product === undefined ? [] : [publication.product]), contentRefKey(ref)]);
5
6
  /** Validate the public identity surface, without reading files or executing source. */
6
7
  function references(manifest, label, requireReviewed) {
7
8
  const fail = () => { throw new Error(`${label} must be a content export manifest with valid, unique public resource references`); };
8
- if (!object(manifest) || manifest.schemaVersion !== 1 || manifest.kind !== 'shoalrun-content-export' || !Array.isArray(manifest.resources) || !manifest.resources.length)
9
+ if (!object(manifest) || manifest.schemaVersion !== 1 && manifest.schemaVersion !== 2 || manifest.kind !== 'shoalrun-content-export' || !Array.isArray(manifest.resources) || !manifest.resources.length)
9
10
  return fail();
10
11
  const publication = manifest.publication;
11
- if (!object(publication) || Object.keys(publication).length !== 3 || !['channel', 'version', 'language'].every(key => nonempty(publication[key])))
12
+ if (!validContentPublication(publication) || !object(publication) || manifest.schemaVersion !== (publication.product === undefined ? 1 : 2))
12
13
  return fail();
13
14
  if (!object(manifest.review) || !['ok', 'required'].includes(String(manifest.review.status)))
14
15
  return fail();
@@ -18,13 +19,13 @@ function references(manifest, label, requireReviewed) {
18
19
  for (const resource of manifest.resources) {
19
20
  if (!object(resource) || !object(resource.ref) || !object(resource.publication))
20
21
  return fail();
21
- if (Object.keys(resource.publication).length !== 3 || !['channel', 'version', 'language'].every(key => resource.publication && resource.publication[key] === publication[key]))
22
+ if (!validContentPublication(resource.publication) || !['channel', 'version', 'language', 'product'].every(key => resource.publication && resource.publication[key] === publication[key]))
22
23
  return fail();
23
24
  const ref = resource.ref;
24
25
  const keys = ref.kind === 'page' ? ['kind', 'documentId'] : ref.kind === 'section' ? ['kind', 'documentId', 'sectionId'] : ref.kind === 'snippet' ? ['kind', 'id'] : [];
25
26
  if (!keys.length || Object.keys(ref).length !== keys.length || !keys.every(key => nonempty(ref[key])))
26
27
  return fail();
27
- const entry = { publication: { channel: publication.channel, version: publication.version, language: publication.language }, ref: { ...ref } };
28
+ const entry = { publication: { channel: publication.channel, version: publication.version, language: publication.language, ...(publication.product !== undefined ? { product: publication.product } : {}) }, ref: { ...ref } };
28
29
  const key = keyFor(entry);
29
30
  if (result.has(key))
30
31
  return fail();
@@ -66,8 +66,10 @@ export function validateExportTarget(value, readerFilters) {
66
66
  };
67
67
  let publication;
68
68
  if (value.publication !== undefined) {
69
- if (!isConfigMapping(value.publication) || Object.keys(value.publication).some(key => !['channel', 'version', 'language'].includes(key)) || ['channel', 'version', 'language'].some(key => typeof value.publication === 'object' && (typeof value.publication[key] !== 'string' || !value.publication[key].trim())))
69
+ if (!isConfigMapping(value.publication) || Object.keys(value.publication).some(key => !['channel', 'version', 'language', 'product'].includes(key)) || ['channel', 'version', 'language'].some(key => typeof value.publication === 'object' && (typeof value.publication[key] !== 'string' || !value.publication[key].trim())))
70
70
  throw new Error('Export publication needs channel, version, and language');
71
+ if (value.publication.product !== undefined && !nonempty(value.publication.product))
72
+ throw new Error('Export publication product must be nonempty text');
71
73
  publication = value.publication;
72
74
  }
73
75
  if (value.apiReview !== undefined && (!isConfigMapping(value.apiReview) || Object.values(value.apiReview).some(digest => typeof digest !== 'string' || !/^[a-f0-9]{64}$/.test(digest))))
@@ -1,9 +1,10 @@
1
+ import { documentKey, samePublication } from './publication-identity.js';
1
2
  import { pruneFeatureTree, profileSelection } from './deployment-profile.js';
2
3
  import { readFile, realpath } from 'node:fs/promises';
3
4
  import path from 'node:path';
4
5
  import { fileURLToPath } from 'node:url';
5
6
  import { loadConfig, explainSegments } from './config.js';
6
- import { configField, isConfigMapping, requirePublicationsSection, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
7
+ import { configField, isConfigMapping, requirePublicationsSection, resolvePublication, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
7
8
  import { defaultLanguage } from './frontmatter.js';
8
9
  import { normalizeBasePath, sitePath } from './site-path.js';
9
10
  import { prepareContentWorkspace } from './content-workspace.js';
@@ -32,13 +33,13 @@ import { isolateExportTree, markExportSource, exportHeadingInventory, preserveEx
32
33
  import { selectSection } from './section-identity.js';
33
34
  import { compareContentManifests } from './content-export-comparison.js';
34
35
  const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
35
- const keyFor = (doc) => `${doc.frontmatter.id}|${doc.variant.channel}|${doc.variant.version}|${doc.variant.language}`;
36
- const resourceIdentity = (item) => JSON.stringify([item.ref.kind, item.ref.kind === 'snippet' ? item.ref.id : item.ref.documentId, item.ref.kind === 'section' ? item.ref.sectionId : null, item.doc.variant.channel, item.doc.variant.version, item.doc.variant.language]);
36
+ const keyFor = (doc) => documentKey(doc.frontmatter.id, doc.variant);
37
+ const resourceIdentity = (item) => JSON.stringify([item.ref.kind, item.ref.kind === 'snippet' ? item.ref.id : item.ref.documentId, item.ref.kind === 'section' ? item.ref.sectionId : null, item.doc.variant.channel, item.doc.variant.version, item.doc.variant.language, ...(item.doc.variant.product === undefined ? [] : [item.doc.variant.product])]);
37
38
  // Pages and their sections share a source; named snippet instances do not.
38
- const sourceKeyFor = (doc, kind = 'document') => JSON.stringify([kind, doc.frontmatter.id, doc.variant.channel, doc.variant.version, doc.variant.language]);
39
+ const sourceKeyFor = (doc, kind = 'document') => JSON.stringify([kind, doc.frontmatter.id, doc.variant.channel, doc.variant.version, doc.variant.language, ...(doc.variant.product === undefined ? [] : [doc.variant.product])]);
39
40
  const selectedSourceKey = (item) => sourceKeyFor(item.doc, item.ref.kind === 'snippet' ? 'snippet' : 'document');
40
41
  const resourceKey = (item) => `resource-${exportDigest(resourceIdentity(item)).slice(0, 24)}`;
41
- const sameVariant = (a, b) => ['channel', 'version', 'language'].every(key => a[key] === b[key]);
42
+ const sameVariant = samePublication;
42
43
  const visitTree = (node, visit) => {
43
44
  if (!node || typeof node !== 'object')
44
45
  return;
@@ -77,9 +78,9 @@ export async function exportContent(configFile, destination, options = {}) {
77
78
  const target = validateExportTarget({ ...raw, ...(options.formats ? { formats: options.formats } : {}), ...(options.documents ? { documents: options.documents } : {}), ...(options.publication ? { publication: options.publication } : {}), ...(options.publicBase ? { publicBase: options.publicBase } : {}) }, config.readerFilters);
78
79
  const language = defaultLanguage(config);
79
80
  const enabled = config.publications.enabled;
80
- if (!Array.isArray(enabled) || !enabled.length || enabled.some(value => !isConfigMapping(value) || typeof value.channel !== 'string' || typeof value.version !== 'string' || value.language !== undefined && typeof value.language !== 'string'))
81
+ if (!Array.isArray(enabled) || !enabled.length || enabled.some(value => !isConfigMapping(value)))
81
82
  throw new Error('publications.enabled must declare valid publication combinations');
82
- const variants = enabled.map(value => ({ channel: value.channel, version: value.version, language: value.language ?? language }));
83
+ const variants = enabled.map(value => resolvePublication(publications, value, language));
83
84
  const unique = [...new Map(variants.map(variant => [JSON.stringify(variant), variant])).values()];
84
85
  const publication = target.publication ?? (unique.length === 1 ? unique[0] : undefined);
85
86
  if (!publication)
@@ -431,7 +432,7 @@ export async function exportContent(configFile, destination, options = {}) {
431
432
  notices += `\n${path.basename(file)}:\n${await readFile(resolvedNotice, 'utf8')}\n`;
432
433
  }
433
434
  artifacts.set('NOTICES.txt', notices);
434
- const manifest = { schemaVersion: 1, kind: 'shoalrun-content-export', publicBase: target.publicBase, publication,
435
+ const manifest = { schemaVersion: publication.product === undefined ? 1 : 2, kind: 'shoalrun-content-export', publicBase: target.publicBase, publication,
435
436
  review: { status: unreviewed.length ? 'required' : 'ok', apis: reviews.map(row => ({ apiId: row.apiId, digest: row.digest })) },
436
437
  resources: records, assets: [...assets.records.values()].sort((a, b) => compare(a.path, b.path)),
437
438
  files: [...artifacts].map(([filename, content]) => ({ path: filename, bytes: Buffer.byteLength(content), digest: exportDigest(content) })).sort((a, b) => compare(a.path, b.path)), diagnostics };
@@ -1,3 +1,4 @@
1
+ import { samePublication } from './publication-identity.js';
1
2
  import { ContentDeliveryError, contentRefKey } from './content-delivery-contract.js';
2
3
  import { contentResourceKey } from './content-rest-contract.js';
3
4
  import { validContentPublication, validContentRef, validateContentResources, safeContentPath } from './content-delivery-validation.js';
@@ -5,7 +6,6 @@ import { freeze, sha256, readBounded } from './content-delivery-transport.js';
5
6
  const digestPattern = /^[a-f0-9]{64}$/;
6
7
  const record = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
7
8
  const exactKeys = (value, keys) => record(value) && Object.keys(value).length === keys.length && Object.keys(value).every(key => keys.includes(key));
8
- const samePublication = (left, right) => left.channel === right.channel && left.version === right.version && left.language === right.language;
9
9
  const invalid = (message) => { throw new ContentDeliveryError('invalid_manifest', message); };
10
10
  /** Preloads a REST inventory and pins all subsequent reads to that revision. */
11
11
  export async function openRestContentSource(options) {
@@ -39,6 +39,8 @@ export async function openRestContentSource(options) {
39
39
  url.pathname = baseUrl.pathname.replace(/\/$/, '') + '/resources' + suffix;
40
40
  for (const key of ['channel', 'version', 'language'])
41
41
  url.searchParams.set(key, publication[key]);
42
+ if (publication.product !== undefined)
43
+ url.searchParams.set('product', publication.product);
42
44
  if (revision !== undefined)
43
45
  url.searchParams.set('revision', revision);
44
46
  return url;
@@ -103,7 +105,7 @@ export async function openRestContentSource(options) {
103
105
  throw error;
104
106
  return invalid('REST inventory is not valid UTF-8 JSON.');
105
107
  }
106
- if (!exactKeys(envelope, ['schemaVersion', 'revision', 'publication', 'resources']) || envelope.schemaVersion !== 1 || !digestPattern.test(envelope.revision ?? '') || !validContentPublication(envelope.publication) || !samePublication(envelope.publication, publication))
108
+ if (!exactKeys(envelope, ['schemaVersion', 'revision', 'publication', 'resources']) || envelope.schemaVersion !== (publication.product === undefined ? 1 : 2) || !digestPattern.test(envelope.revision ?? '') || !validContentPublication(envelope.publication) || !samePublication(envelope.publication, publication))
107
109
  invalid('Invalid REST inventory identity.');
108
110
  if (requestedRevision !== undefined && requestedRevision !== envelope.revision)
109
111
  throw new ContentDeliveryError('stale_revision', 'REST inventory differs from the requested revision.');
@@ -6,13 +6,13 @@ export type ContentRestEntry = {
6
6
  resource: ContentResource;
7
7
  };
8
8
  export type ContentRestList = {
9
- schemaVersion: 1;
9
+ schemaVersion: 1 | 2;
10
10
  revision: string;
11
11
  publication: ContentPublication;
12
12
  resources: ContentRestEntry[];
13
13
  };
14
14
  export type ContentRestResource = {
15
- schemaVersion: 1;
15
+ schemaVersion: 1 | 2;
16
16
  revision: string;
17
17
  publication: ContentPublication;
18
18
  key: string;
@@ -1,9 +1,10 @@
1
1
  import { ContentDeliveryError, contentRefKey } from './content-delivery-contract.js';
2
+ import { validContentPublication } from './content-delivery-validation.js';
2
3
  import { contentResourceKey } from './content-rest-contract.js';
3
- const publicationKey = (publication) => JSON.stringify([publication.channel, publication.version, publication.language]);
4
+ const publicationKey = (publication) => JSON.stringify([publication.channel, publication.version, publication.language, ...(publication.product === undefined ? [] : [publication.product])]);
4
5
  const digest = async (bytes) => [...new Uint8Array(await crypto.subtle.digest('SHA-256', bytes))].map(value => value.toString(16).padStart(2, '0')).join('');
5
6
  const encoder = new TextEncoder();
6
- const validPublication = (value) => value && Object.keys(value).sort().join(',') === 'channel,language,version' && Object.values(value).every(part => typeof part === 'string' && part.length > 0 && part.length <= 2048);
7
+ const validPublication = validContentPublication;
7
8
  const canonical = (value) => Array.isArray(value) ? value.map(canonical) : value && typeof value === 'object' ? Object.fromEntries(Object.keys(value).sort().map(key => [key, canonical(value[key])])) : value;
8
9
  const same = (left, right) => JSON.stringify(canonical(left)) === JSON.stringify(canonical(right));
9
10
  /** Serve already-approved, pinned snapshots. The caller retains source ownership. */
@@ -38,16 +39,20 @@ export function createContentRestHandler(options) {
38
39
  const parts = url.pathname.slice(prefix.length).split('/').slice(1);
39
40
  if (parts.length !== 0 && parts.length !== 1 && !(parts.length === 3 && parts[1] === 'representations'))
40
41
  return error(404, 'not_found', 'Unknown content route.');
41
- const allowed = new Set(['channel', 'version', 'language', 'revision']);
42
+ const allowed = new Set(['channel', 'version', 'language', 'product', 'revision']);
42
43
  if ([...url.searchParams.keys()].some(key => !allowed.has(key) || url.searchParams.getAll(key).length !== 1))
43
44
  return error(400, 'invalid_request', 'Unknown or repeated query parameter.');
44
45
  const publication = Object.fromEntries(['channel', 'version', 'language'].map(key => [key, url.searchParams.get(key)]));
45
- if (Object.values(publication).some(value => !value || value.length > 2048))
46
+ if (url.searchParams.has('product'))
47
+ publication.product = url.searchParams.get('product');
48
+ if (!validPublication(publication))
46
49
  return error(400, 'invalid_request', 'channel, version, and language are required.');
47
50
  const revision = url.searchParams.get('revision');
48
51
  if (revision !== null && !/^[a-f0-9]{64}$/.test(revision) || parts.length > 0 && revision === null)
49
52
  return error(400, 'invalid_request', 'A valid revision is required for resource requests.');
50
53
  const selected = publications.get(publicationKey(publication));
54
+ if (!selected && publication.product === undefined && [...publications.values()].some(item => item.publication.product !== undefined && item.publication.channel === publication.channel && item.publication.version === publication.version && item.publication.language === publication.language))
55
+ return error(400, 'invalid_request', 'product is required for product-scoped publications.');
51
56
  if (!selected)
52
57
  return error(404, 'not_found', 'Publication not found.');
53
58
  if (revision !== null && revision !== selected.revision)
@@ -59,9 +64,9 @@ export function createContentRestHandler(options) {
59
64
  let body;
60
65
  let mediaType = 'application/json';
61
66
  if (!parts.length)
62
- body = JSON.stringify({ schemaVersion: 1, revision: selected.revision, publication: selected.publication, resources: selected.resources });
67
+ body = JSON.stringify({ schemaVersion: selected.publication.product === undefined ? 1 : 2, revision: selected.revision, publication: selected.publication, resources: selected.resources });
63
68
  else if (parts.length === 1)
64
- body = JSON.stringify({ schemaVersion: 1, revision: selected.revision, publication: selected.publication, ...resource });
69
+ body = JSON.stringify({ schemaVersion: selected.publication.product === undefined ? 1 : 2, revision: selected.revision, publication: selected.publication, ...resource });
65
70
  else {
66
71
  const format = parts[2];
67
72
  if (!['html', 'markdown'].includes(format) || !resource.resource.representations[format])
@@ -3,6 +3,7 @@ import type { SubjectDeprecation, ResolvedSubjectDeprecation } from './subject-d
3
3
  import type { ReaderSelection } from './reader-filters.js';
4
4
  import type { StandaloneSectionDeclaration } from './section-identity.js';
5
5
  export type Variant = {
6
+ product?: string;
6
7
  channel: string;
7
8
  version: string;
8
9
  language: string;
@@ -18,9 +19,14 @@ export type Frontmatter = {
18
19
  updated?: string;
19
20
  verified?: string;
20
21
  releaseVersion?: string;
22
+ availability?: {
23
+ since?: string;
24
+ through?: string;
25
+ };
21
26
  channel?: string;
22
27
  version?: string;
23
28
  publications?: Array<{
29
+ product?: string;
24
30
  channel: string;
25
31
  version: string;
26
32
  }>;
@@ -92,6 +98,13 @@ export type PublicationRoutingConfig = {
92
98
  versions: Record<string, {
93
99
  pathPrefix?: string;
94
100
  }>;
101
+ products?: Record<string, {
102
+ pathPrefix: string;
103
+ defaultVersion: string;
104
+ versions: Record<string, {
105
+ pathPrefix?: string;
106
+ }>;
107
+ }>;
95
108
  };
96
109
  };
97
110
  export declare function readDocument(file: string, frontmatterConfig?: unknown, enrich?: (source: Record<string, unknown>) => Promise<Record<string, unknown>>, sourceText?: string): Promise<{
@@ -26,7 +26,10 @@ export async function readDocument(file, frontmatterConfig, enrich, sourceText)
26
26
  }
27
27
  export function routeFor(frontmatter, variant, config) {
28
28
  const channel = config.publications.channels[variant.channel];
29
- const version = config.publications.versions[variant.version];
29
+ const product = variant.product === undefined ? undefined : config.publications.products?.[variant.product];
30
+ if (variant.product !== undefined && !product)
31
+ throw new Error(`Unknown publication product ${variant.product}`);
32
+ const version = (product?.versions ?? config.publications.versions)[variant.version];
30
33
  if (!channel || !version)
31
34
  throw new Error(`Unknown publication ${variant.channel}/${variant.version}`);
32
35
  const slug = frontmatter.slug;
@@ -35,7 +38,7 @@ export function routeFor(frontmatter, variant, config) {
35
38
  if (/^\/(?:\.well-known|api)(?:\/|$)/i.test(slug))
36
39
  throw new Error(`${frontmatter.id}: slug uses a reserved discovery path`);
37
40
  const languagePrefix = variant.language === defaultLanguage(config) ? '' : `/${variant.language}`;
38
- const parts = [normalizeBasePath(config.site.basePath), languagePrefix, channel.pathPrefix ?? '', version.pathPrefix ?? '', slug].filter(Boolean);
41
+ const parts = [normalizeBasePath(config.site.basePath), languagePrefix, product?.pathPrefix ?? '', channel.pathPrefix ?? '', version.pathPrefix ?? '', slug].filter(Boolean);
39
42
  const normalized = '/' + parts.join('/').replace(/\/+/g, '/').replace(/^\//, '').replace(/\/$/, '');
40
43
  return normalized === '/' ? '/' : normalized;
41
44
  }
@@ -47,7 +47,9 @@ export declare function prepareContentWorkspace({ base, basePath, config, loaded
47
47
  path: string;
48
48
  [key: string]: unknown;
49
49
  };
50
+ product?: string;
50
51
  publications?: Array<{
52
+ product?: string;
51
53
  channel: string;
52
54
  version: string;
53
55
  source: {
@@ -90,7 +92,9 @@ export declare function prepareContentWorkspace({ base, basePath, config, loaded
90
92
  path: string;
91
93
  [key: string]: unknown;
92
94
  };
95
+ product?: string;
93
96
  publications?: Array<{
97
+ product?: string;
94
98
  channel: string;
95
99
  version: string;
96
100
  source: {
@@ -134,7 +138,9 @@ export declare function prepareContentWorkspace({ base, basePath, config, loaded
134
138
  path: string;
135
139
  [key: string]: unknown;
136
140
  };
141
+ product?: string;
137
142
  publications?: Array<{
143
+ product?: string;
138
144
  channel: string;
139
145
  version: string;
140
146
  source: {
@@ -173,7 +179,9 @@ export declare function prepareContentWorkspace({ base, basePath, config, loaded
173
179
  path: string;
174
180
  [key: string]: unknown;
175
181
  };
182
+ product?: string;
176
183
  publications?: Array<{
184
+ product?: string;
177
185
  channel: string;
178
186
  version: string;
179
187
  source: {
@@ -216,7 +224,9 @@ export declare function prepareContentWorkspace({ base, basePath, config, loaded
216
224
  path: string;
217
225
  [key: string]: unknown;
218
226
  };
227
+ product?: string;
219
228
  publications?: Array<{
229
+ product?: string;
220
230
  channel: string;
221
231
  version: string;
222
232
  source: {
@@ -270,7 +280,9 @@ export declare function prepareContentWorkspace({ base, basePath, config, loaded
270
280
  path: string;
271
281
  [key: string]: unknown;
272
282
  };
283
+ product?: string;
273
284
  publications?: Array<{
285
+ product?: string;
274
286
  channel: string;
275
287
  version: string;
276
288
  source: {
@@ -1,3 +1,4 @@
1
+ import { documentKey } from './publication-identity.js';
1
2
  import { matchesFeatures } from './deployment-profile.js';
2
3
  import path from 'node:path';
3
4
  import { readFile } from 'node:fs/promises';
@@ -6,7 +7,7 @@ import { planAuthoredDocuments } from './publication-plan.js';
6
7
  import { materializeApiReferences } from './api-publication-plan.js';
7
8
  import { explainSegments } from './config.js';
8
9
  import { validateSnippetConfig } from './snippets.js';
9
- const keyFor = (id, variant) => `${id}|${variant.channel}|${variant.version}|${variant.language}`;
10
+ const keyFor = documentKey;
10
11
  /** Shared source resolution. No website navigation, styles, hosting or provider setup. */
11
12
  export async function prepareContentWorkspace({ base, basePath, config, loaded, variants, language, readerFilters, contentFilter, metadataProvider, metadataDependencies, sourceOverrides, authoringFiles, allowRouteCollisions }) {
12
13
  const { docs, knownDocumentIds, knownDocumentTypes, authoredOperationIds, routeOwners, contentDir } = await planAuthoredDocuments({
package/dist/content.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { publicationKey } from './publication-identity.js';
1
2
  import { fictionalDocument, resolveLlmsDiscovery } from './llms-discovery.js';
2
3
  import YAML from 'yaml';
3
4
  import { nativePublicFields, protectedMetadataRoots, publicFrontmatterPaths } from './frontmatter.js';
@@ -8,7 +9,7 @@ export { transformMdx } from './component-transform.js';
8
9
  export { renderHtml } from './html-renderer.js';
9
10
  export { buildHtmlPage, shareCardText, typeLabel } from './page-renderer.js';
10
11
  // API separators are visually hidden punctuation; join them to the preceding text so search reads "integer; default: 0".
11
- const variantKey = (variant) => `${variant.channel}|${variant.version}|${variant.language}`;
12
+ const variantKey = publicationKey;
12
13
  const plainText = (html) => html.replace(/<(script|style)[^]*?<\/\1>/g, ' ').replace(/(?:<\/[a-z]+>)?<span class="api-separator">([^<]*)<\/span>/g, '$1').replace(/<[^>]+>/g, ' ')
13
14
  .replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#x27;|&#39;/g, "'").replace(/&amp;/g, '&').replace(/\s+/g, ' ').trim();
14
15
  // One compact record per published page; headings allow results to deep-link into a section.
@@ -54,7 +55,7 @@ export function projectMetadata(doc, config) {
54
55
  throw new Error('Markdown metadata projection must be a mapping');
55
56
  const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
56
57
  const safePath = (value) => /^[A-Za-z_][A-Za-z0-9_-]*(?:\.[A-Za-z_][A-Za-z0-9_-]*)*$/.test(value);
57
- const publicationFields = new Set(['channel', 'version', 'language', 'canonicalUrl']);
58
+ const publicationFields = new Set(['product', 'channel', 'version', 'language', 'canonicalUrl']);
58
59
  const approved = publicFrontmatterPaths(config.frontmatter);
59
60
  const validateSource = (source) => {
60
61
  if (!safePath(source))
@@ -1,3 +1,4 @@
1
+ import { samePublication } from './publication-identity.js';
1
2
  const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
2
3
  const keys = (value, allowed) => Object.keys(value).every(key => allowed.includes(key));
3
4
  const validId = (value) => typeof value === 'string' && /^[a-z][a-z0-9-]*$/.test(value);
@@ -35,7 +36,7 @@ export function cookbookChooserComponent(node, file) {
35
36
  return { type: 'docCookbookChooser', id: attributes[0].value, sourceFile: file };
36
37
  }
37
38
  export function resolveCookbookTree(tree, current, documents, cookbooks, targets) {
38
- const sameVariant = (a, b) => a.variant.channel === b.variant.channel && a.variant.version === b.variant.version && a.variant.language === b.variant.language;
39
+ const sameVariant = (a, b) => samePublication(a.variant, b.variant);
39
40
  const walk = (node) => {
40
41
  if (node.type !== 'docCookbookChooser')
41
42
  return node.children ? { ...node, children: node.children.map(walk) } : node;
@@ -5,6 +5,7 @@ export type FeatureRequirements = {
5
5
  export type FeatureContext = {
6
6
  requireClassification?: boolean;
7
7
  classificationPublications?: Array<{
8
+ product?: string;
8
9
  channel: string;
9
10
  version: string;
10
11
  language: string;
@@ -49,4 +50,4 @@ export declare function profileSelection(resolution: ProfileResolution | undefin
49
50
  }[];
50
51
  } | undefined;
51
52
  /** A profile is data, never executable configuration or a directory to discover. */
52
- export declare function resolveDeploymentProfile(settings: unknown, config: Record<string, any>, declaringFile: string, profileFile?: string): Promise<ProfileResolution | undefined>;
53
+ export declare function resolveDeploymentProfile(settings: unknown, config: Record<string, any>, declaringFile: string, profileFile?: string, onDependency?: (file: string) => void): Promise<ProfileResolution | undefined>;
@@ -1,3 +1,5 @@
1
+ import { resolvePublication } from './compiler-config.js';
2
+ import { publicationKey } from './publication-identity.js';
1
3
  import { readFile, lstat, realpath } from 'node:fs/promises';
2
4
  import path from 'node:path';
3
5
  import { createHash } from 'node:crypto';
@@ -95,7 +97,7 @@ export function profileSelection(resolution) {
95
97
  return { schemaVersion: 1, profileDigest: resolution.digest, features: [...resolution.context.grants].sort(), provenance: resolution.context.provenance, decisions: resolution.context.decisions };
96
98
  }
97
99
  /** A profile is data, never executable configuration or a directory to discover. */
98
- export async function resolveDeploymentProfile(settings, config, declaringFile, profileFile) {
100
+ export async function resolveDeploymentProfile(settings, config, declaringFile, profileFile, onDependency) {
99
101
  if (settings === undefined) {
100
102
  if (profileFile)
101
103
  throw new Error('--profile requires profiles.manifest in the shared configuration');
@@ -108,6 +110,7 @@ export async function resolveDeploymentProfile(settings, config, declaringFile,
108
110
  if (settings[setting] !== undefined && typeof settings[setting] !== 'boolean')
109
111
  throw new Error(`profiles.${setting} must be boolean`);
110
112
  const manifestFile = path.resolve(path.dirname(declaringFile), settings.manifest);
113
+ onDependency?.(manifestFile);
111
114
  const manifestBytes = await readFile(manifestFile);
112
115
  const manifest = parseYaml(manifestBytes.toString('utf8'), manifestFile);
113
116
  keys(manifest, ['schemaVersion', 'features', 'skus'], 'SKU manifest');
@@ -142,13 +145,15 @@ export async function resolveDeploymentProfile(settings, config, declaringFile,
142
145
  const context = { features, digest, pruneNavigation: settings.pruneNavigation ?? false, decisions: [], provenance: Object.create(null) };
143
146
  context.requireClassification = settings.requireClassification ?? false;
144
147
  if (context.requireClassification)
145
- context.classificationPublications = (config.publications?.enabled ?? []).map((entry) => ({ channel: entry.channel, version: entry.version, language: entry.language ?? defaultLanguage(config) }));
148
+ context.classificationPublications = (config.publications?.enabled ?? []).map((entry) => resolvePublication(config.publications, entry, defaultLanguage(config)));
146
149
  if (!profileFile) {
147
150
  if (settings.required !== false)
148
151
  throw new Error('This project requires an explicit --profile FILE');
149
152
  return { context, overlay: {}, dependencies: [manifestFile], assetFiles: [], digest };
150
153
  }
154
+ onDependency?.(path.resolve(profileFile));
151
155
  const file = await realpath(path.resolve(profileFile));
156
+ onDependency?.(file);
152
157
  const bytes = await readFile(file);
153
158
  const profile = parseYaml(bytes.toString('utf8'), file);
154
159
  profileData(profile);
@@ -185,7 +190,12 @@ export async function resolveDeploymentProfile(settings, config, declaringFile,
185
190
  const overlay = {};
186
191
  const assetFiles = [];
187
192
  if (profile.site !== undefined) {
188
- keys(profile.site, ['title', 'origin', 'basePath', 'favicon', 'logo', 'header', 'footer', 'indexing'], 'Profile site');
193
+ keys(profile.site, ['title', 'origin', 'basePath', 'favicon', 'logo', 'header', 'footer', 'indexing', 'publicationSelector'], 'Profile site');
194
+ if (profile.site.publicationSelector !== undefined) {
195
+ keys(profile.site.publicationSelector, ['showLanguage'], 'Profile site.publicationSelector');
196
+ if (profile.site.publicationSelector.showLanguage !== undefined && typeof profile.site.publicationSelector.showLanguage !== 'boolean')
197
+ throw new Error('Profile site.publicationSelector.showLanguage must be boolean');
198
+ }
189
199
  if (profile.site.title !== undefined && (typeof profile.site.title !== 'string' || !profile.site.title.trim()))
190
200
  throw new Error('Profile site.title must be nonempty text');
191
201
  if (profile.site.indexing !== undefined && typeof profile.site.indexing !== 'boolean')
@@ -221,11 +231,31 @@ export async function resolveDeploymentProfile(settings, config, declaringFile,
221
231
  throw new Error('Profile asset must stay within the profile directory');
222
232
  // Explicit assets only. Symlinks must not introduce an undeclared capture root.
223
233
  let current = target;
234
+ const ancestry = [];
224
235
  while (current !== path.dirname(file)) {
225
- if ((await lstat(current)).isSymbolicLink())
226
- throw new Error('Profile assets must not use symlinks');
236
+ ancestry.unshift(current);
227
237
  current = path.dirname(current);
228
238
  }
239
+ for (const entry of ancestry) {
240
+ let info;
241
+ try {
242
+ info = await lstat(entry);
243
+ }
244
+ catch (error) {
245
+ // Every existing ancestor has passed the containment/symlink check.
246
+ // Watch only this declared target so creating it can repair a preview.
247
+ if (error.code === 'ENOENT')
248
+ onDependency?.(target);
249
+ throw error;
250
+ }
251
+ if (info.isSymbolicLink())
252
+ throw new Error('Profile assets must not use symlinks');
253
+ if (entry !== target && !info.isDirectory()) {
254
+ onDependency?.(target);
255
+ throw new Error('Profile asset parents must be directories');
256
+ }
257
+ }
258
+ onDependency?.(target);
229
259
  if (!(await lstat(target)).isFile())
230
260
  throw new Error(`Profile ${setting} must be a regular file`);
231
261
  assetFiles.push(target);
@@ -257,13 +287,13 @@ export async function resolveDeploymentProfile(settings, config, declaringFile,
257
287
  keys(profile.publications, ['enabled'], 'Profile publications');
258
288
  const enabled = profile.publications.enabled;
259
289
  const language = defaultLanguage(config);
260
- const coordinate = (value) => JSON.stringify([value.channel, value.version, value.language ?? language]);
290
+ const coordinate = (value) => publicationKey(resolvePublication(config.publications, value, language));
261
291
  if (!Array.isArray(enabled) || !enabled.length)
262
292
  throw new Error('Profile publications.enabled must be a nonempty subset of shared publications.enabled');
263
293
  const selected = new Set();
264
294
  for (const variant of enabled) {
265
- keys(variant, ['channel', 'version', 'language'], 'Profile publication');
266
- if (typeof variant.channel !== 'string' || typeof variant.version !== 'string' || (variant.language !== undefined && typeof variant.language !== 'string') || !config.publications?.enabled?.some((entry) => coordinate(entry) === coordinate(variant)))
295
+ keys(variant, ['product', 'channel', 'version', 'language'], 'Profile publication');
296
+ if (typeof variant.channel !== 'string' || (variant.version !== undefined && typeof variant.version !== 'string') || (variant.product !== undefined && typeof variant.product !== 'string') || (variant.language !== undefined && typeof variant.language !== 'string') || !config.publications?.enabled?.some((entry) => coordinate(entry) === coordinate(variant)))
267
297
  throw new Error('Profile publication is not enabled by the shared configuration');
268
298
  const key = coordinate(variant);
269
299
  if (selected.has(key))
package/dist/dev.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  import type { Server } from 'node:http';
2
- export declare function startDev(configFile: string, outputDirectory: string, host?: string, port?: number): Promise<Server>;
2
+ export declare function startDev(configFile: string, outputDirectory: string, host?: string, port?: number, options?: {
3
+ profile?: string;
4
+ }): Promise<Server>;