@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
package/dist/cli.js CHANGED
@@ -40,7 +40,7 @@ import { buildChunkIndex, embeddingInput } from './index-build.js';
40
40
  import { createProvider, embedChunkIndex, readEmbeddings } from './embeddings.js';
41
41
  import { embeddingProviderConfig, queryProviderConfig, validateRetrieval } from './retrieval-config.js';
42
42
  import { defaultLogNotice, validateChat } from './chat-config.js';
43
- import { createSession, turnstileVerifier } from './turnstile.js';
43
+ import { createSession, turnstilePreviewVerifier } from './turnstile.js';
44
44
  import { adaptiveChallenge } from './budget.js';
45
45
  import { validateReaderFilters } from './reader-filters.js';
46
46
  import { askQuestion } from './ask.js';
@@ -142,11 +142,19 @@ try {
142
142
  const args = [subcommand, ...rest].filter((item) => item !== undefined);
143
143
  const positional = [];
144
144
  let port = defaultPort();
145
+ let profile;
145
146
  for (let index = 0; index < args.length; index++) {
146
- if (args[index] === '--port') {
147
+ if (args[index] === '--port' || args[index] === '--profile') {
148
+ const option = args[index];
147
149
  if (!args[index + 1] || args[index + 1].startsWith('--'))
148
- throw new Error('Usage: shoalrun dev [config] [output] [--port PORT]');
149
- port = Number(args[++index]);
150
+ throw new Error('Usage: shoalrun dev [config] [output] [--port PORT] [--profile FILE]');
151
+ if (option === '--profile') {
152
+ if (profile !== undefined)
153
+ throw new Error('Duplicate dev option --profile');
154
+ profile = args[++index];
155
+ }
156
+ else
157
+ port = Number(args[++index]);
150
158
  }
151
159
  else if (args[index].startsWith('--'))
152
160
  throw new Error(`Unknown dev option ${args[index]}`);
@@ -154,8 +162,8 @@ try {
154
162
  positional.push(args[index]);
155
163
  }
156
164
  if (positional.length > 2)
157
- throw new Error('Usage: shoalrun dev [config] [output] [--port PORT]');
158
- await startDev(positional[0] ?? 'docs.config.yaml', positional[1] ?? 'site-dist', '127.0.0.1', port);
165
+ throw new Error('Usage: shoalrun dev [config] [output] [--port PORT] [--profile FILE]');
166
+ await startDev(positional[0] ?? 'docs.config.yaml', positional[1] ?? 'site-dist', '127.0.0.1', port, { profile });
159
167
  }
160
168
  else if (command === 'vercel' && subcommand === 'build') {
161
169
  // --chat adds the optional answer function: it needs chat and retrieval settings and the embedding key at build time.
@@ -261,7 +269,7 @@ try {
261
269
  if (publicPreview) {
262
270
  chatConfigForPreview = chatConfig;
263
271
  publicSettings = { siteKey: '1x00000000000000000000AA', ...(chatConfig?.challenge?.when === 'always' ? { prewarm: true } : {}), notice: chatConfig?.log?.notice ?? defaultLogNotice, ...(chatConfig?.panel ? { panel: chatConfig.panel } : {}) };
264
- const verify = turnstileVerifier({ secret: '1x0000000000000000000000000000000AA' });
272
+ const verify = turnstilePreviewVerifier();
265
273
  challenge = ({ token, ip }) => verify({ token, ip });
266
274
  }
267
275
  const handler = createAskHandler({ hosts, exposeErrors: true, ...(publicPreview ? { response: 'public', challenge, session: createSession({ secret: '1x0000000000000000000000000000000AA' }), ...(chatConfigForPreview?.challenge?.when === 'always' || !setup.budget ? {} : { challengeNeeded: adaptiveChallenge(setup.budget, { freeQuestions: chatConfigForPreview?.challenge?.freeQuestions, busyShare: chatConfigForPreview?.challenge?.busyShare }) }) } : {}), ...(log ? { record: event => log.write(event) } : {}), ...(setup.budget ? { budget: setup.budget } : {}), answer: (question, history, context) => askQuestion({ question, history, ...setup.options, modelAllowed: context.modelAllowed, signal: context.signal, ...(publicPreview ? { requireCitations: true } : {}) }) });
@@ -372,9 +380,9 @@ try {
372
380
  }
373
381
  else if (command === 'search') {
374
382
  if (!subcommand || !rest[0] || rest[0].startsWith('--'))
375
- throw new Error('Usage: shoalrun search <site-directory> <query> [--channel C] [--version V] [--language L] [--limit N]');
383
+ throw new Error('Usage: shoalrun search <site-directory> <query> [--product P] [--channel C] [--version V] [--language L] [--limit N]');
376
384
  const options = {};
377
- const names = { '--channel': 'channel', '--version': 'version', '--language': 'language', '--limit': 'limit' };
385
+ const names = { '--product': 'product', '--channel': 'channel', '--version': 'version', '--language': 'language', '--limit': 'limit' };
378
386
  for (let index = 1; index < rest.length; index += 2) {
379
387
  const flag = rest[index];
380
388
  const value = rest[index + 1];
@@ -432,7 +440,7 @@ try {
432
440
  process.stdout.write(JSON.stringify({ status: 'ok', documents: result.documents, chunks: result.index.chunks.length, sourceDigest: result.index.sourceDigest, publications, output: result.output, ...(embeddings ? { embeddings } : {}) }, null, 2) + '\n');
433
441
  }
434
442
  else if (command === 'ask') {
435
- const usage = 'Usage: shoalrun ask <site-directory> "<question>" [--config FILE] [--model MODEL] [--passages N] [--reader-view FACET=CHOICE[,CHOICE]]... [--channel C --version V --language L] [--no-rerank] [--no-direct] [--no-escalate] [--no-cards] [--json]';
443
+ const usage = 'Usage: shoalrun ask <site-directory> "<question>" [--config FILE] [--model MODEL] [--passages N] [--reader-view FACET=CHOICE[,CHOICE]]... [--product P] [--channel C --version V --language L] [--no-rerank] [--no-direct] [--no-escalate] [--no-cards] [--json]';
436
444
  if (!subcommand || subcommand.startsWith('--') || !rest[0] || rest[0].startsWith('--'))
437
445
  throw new Error(usage);
438
446
  const values = {};
@@ -449,14 +457,14 @@ try {
449
457
  views.push(value);
450
458
  continue;
451
459
  }
452
- if (!['--config', '--model', '--passages', '--channel', '--version', '--language'].includes(flag) || !value || value.startsWith('--'))
460
+ if (!['--config', '--model', '--passages', '--product', '--channel', '--version', '--language'].includes(flag) || !value || value.startsWith('--'))
453
461
  throw new Error(usage);
454
462
  if (values[flag] !== undefined)
455
463
  throw new Error(`Duplicate ask option ${flag}`);
456
464
  values[flag] = value;
457
465
  }
458
466
  const configFile = values['--config'] ?? await discoverConfig(process.cwd()).catch(() => { throw new Error('No docs.config.yaml found; pass --config FILE. `ask` reads its chat provider and model from the config'); });
459
- const setup = await prepareAsk({ siteDirectory: subcommand, configFile, model: values['--model'], passages: values['--passages'] === undefined ? undefined : Number(values['--passages']), channel: values['--channel'], version: values['--version'], language: values['--language'], noRerank: switches.has('--no-rerank'), noDirect: switches.has('--no-direct'), noEscalate: switches.has('--no-escalate'), noCards: switches.has('--no-cards'), readerView: parseReaderView(views) });
467
+ const setup = await prepareAsk({ siteDirectory: subcommand, configFile, model: values['--model'], passages: values['--passages'] === undefined ? undefined : Number(values['--passages']), product: values['--product'], channel: values['--channel'], version: values['--version'], language: values['--language'], noRerank: switches.has('--no-rerank'), noDirect: switches.has('--no-direct'), noEscalate: switches.has('--no-escalate'), noCards: switches.has('--no-cards'), readerView: parseReaderView(views) });
460
468
  for (const note of setup.notes)
461
469
  process.stderr.write(`${note}\n`);
462
470
  const chat = setup.chat;
@@ -544,7 +552,7 @@ try {
544
552
  }
545
553
  }
546
554
  else if (command === 'answers') {
547
- const usage = 'Usage: shoalrun answers <site-directory> --questions FILE [--config FILE] [--model MODEL] [--reader-view FACET=CHOICE[,CHOICE]]...';
555
+ const usage = 'Usage: shoalrun answers <site-directory> --questions FILE [--config FILE] [--model MODEL] [--product P --channel C --version V --language L] [--reader-view FACET=CHOICE[,CHOICE]]...';
548
556
  if (!subcommand || subcommand.startsWith('--'))
549
557
  throw new Error(usage);
550
558
  const values = {};
@@ -556,7 +564,7 @@ try {
556
564
  views.push(value);
557
565
  continue;
558
566
  }
559
- if (!['--questions', '--config', '--model'].includes(flag) || !value || value.startsWith('--'))
567
+ if (!['--questions', '--config', '--model', '--product', '--channel', '--version', '--language'].includes(flag) || !value || value.startsWith('--'))
560
568
  throw new Error(usage);
561
569
  if (values[flag] !== undefined)
562
570
  throw new Error(`Duplicate answers option ${flag}`);
@@ -567,7 +575,7 @@ try {
567
575
  const configFile = values['--config'] ?? await discoverConfig(process.cwd()).catch(() => { throw new Error('No docs.config.yaml found; pass --config FILE. `answers` reads its chat provider and model from the config'); });
568
576
  const questions = parseCardQuestions(await readFile(values['--questions'], 'utf8'));
569
577
  // Cards are polished answers, so they come from the model, not from a direct excerpt, and never from another card.
570
- const setup = await prepareAsk({ siteDirectory: subcommand, configFile, model: values['--model'], noCards: true, noDirect: true, readerView: parseReaderView(views) });
578
+ const setup = await prepareAsk({ siteDirectory: subcommand, configFile, model: values['--model'], product: values['--product'], channel: values['--channel'], version: values['--version'], language: values['--language'], noCards: true, noDirect: true, readerView: parseReaderView(views) });
571
579
  for (const note of setup.notes)
572
580
  process.stderr.write(`${note}\n`);
573
581
  if (!setup.embedTexts || !setup.embedding)
@@ -620,7 +628,7 @@ try {
620
628
  if ((!flag?.startsWith('--') && flag !== '-n') || !value || value.startsWith('--'))
621
629
  throw new Error(`Scaffold option ${flag ?? ''} needs a value`);
622
630
  const name = flag === '-n' ? 'new' : flag.slice(2);
623
- if (!['new', 'config', 'id', 'title', 'summary', 'slug', 'channel', 'version', 'language', 'operation'].includes(name))
631
+ if (!['new', 'config', 'id', 'title', 'summary', 'slug', 'product', 'channel', 'version', 'language', 'operation'].includes(name))
624
632
  throw new Error(`Unknown scaffold option ${flag}`);
625
633
  if (name === 'operation')
626
634
  operations.push(value);
@@ -631,7 +639,7 @@ try {
631
639
  }
632
640
  if (shortForm && !options.new)
633
641
  throw new Error('Scaffold needs -n or --new with a target file');
634
- const overrides = { id: options.id, title: options.title, summary: options.summary, slug: options.slug, channel: options.channel, version: options.version, language: options.language, ...(operations.length ? { operations } : {}) };
642
+ const overrides = { id: options.id, title: options.title, summary: options.summary, slug: options.slug, product: options.product, channel: options.channel, version: options.version, language: options.language, ...(operations.length ? { operations } : {}) };
635
643
  const result = shortForm
636
644
  ? await scaffoldFromPath(options.config ?? await discoverConfig(process.cwd()), subcommand, options.new, Object.fromEntries(Object.entries(overrides).filter(([, value]) => value !== undefined)))
637
645
  : await scaffold(rest[0], subcommand, rest[1], overrides);
@@ -691,9 +699,20 @@ try {
691
699
  process.exitCode = 1;
692
700
  }
693
701
  else if (command === 'api' && subcommand === 'select') {
694
- if (!rest[0] || !rest[1] || rest[2] !== '--output' || !rest[3] || rest.length !== 4)
695
- throw new Error('Usage: shoalrun api select <api-id> <config> --output <selection.yaml>');
696
- const result = await selectApiReferences(rest[1], rest[0], rest[3]);
702
+ const usage = 'Usage: shoalrun api select <api-id> <config> --output FILE [--product P --channel C --version V --language L]';
703
+ if (!rest[0] || !rest[1])
704
+ throw new Error(usage);
705
+ const flags = {};
706
+ for (let i = 2; i < rest.length; i += 2) {
707
+ const flag = rest[i];
708
+ const value = rest[i + 1];
709
+ if (!['--output', '--product', '--channel', '--version', '--language'].includes(flag) || !value || value.startsWith('--') || flags[flag])
710
+ throw new Error(usage);
711
+ flags[flag] = value;
712
+ }
713
+ if (!flags['--output'])
714
+ throw new Error(usage);
715
+ const result = await selectApiReferences(rest[1], rest[0], flags['--output'], { product: flags['--product'], channel: flags['--channel'], version: flags['--version'], language: flags['--language'] });
697
716
  process.stdout.write(JSON.stringify({ status: 'ok', ...result }, null, 2) + '\n');
698
717
  }
699
718
  else if (command === 'api' && subcommand === 'materialize') {
@@ -710,12 +729,18 @@ try {
710
729
  continue;
711
730
  }
712
731
  const value = rest[++index];
713
- if (!['--operation', '--route', '--output'].includes(flag) || !value || value.startsWith('--'))
732
+ if (!['--operation', '--route', '--output', '--product', '--channel', '--version', '--language'].includes(flag) || !value || value.startsWith('--'))
714
733
  throw new Error(usage);
715
734
  if (flag === '--operation')
716
735
  options.operations.push(value);
717
736
  else if (flag === '--route')
718
737
  options.routes.push(value);
738
+ else if (flag !== '--output') {
739
+ const key = flag.slice(2);
740
+ if (options[key])
741
+ throw new Error(`Duplicate ${flag}`);
742
+ options[key] = value;
743
+ }
719
744
  else if (options.output)
720
745
  throw new Error('Duplicate --output');
721
746
  else
@@ -725,7 +750,7 @@ try {
725
750
  process.stdout.write(JSON.stringify({ status: 'ok', ...result }, null, 2) + '\n');
726
751
  }
727
752
  else if (command === 'operation' && subcommand === 'inspect') {
728
- const usage = 'Usage: shoalrun operation inspect <id> [config] [--channel C] [--version V] [--language L]';
753
+ const usage = 'Usage: shoalrun operation inspect <id> [config] [--product P] [--channel C] [--version V] [--language L]';
729
754
  if (!rest[0] || rest[0].startsWith('--'))
730
755
  throw new Error(usage);
731
756
  const hasConfig = rest[1] !== undefined && !rest[1].startsWith('--');
@@ -734,7 +759,7 @@ try {
734
759
  const flag = rest[index];
735
760
  const value = rest[index + 1];
736
761
  const name = flag.slice(2);
737
- if (!['--channel', '--version', '--language'].includes(flag))
762
+ if (!['--product', '--channel', '--version', '--language'].includes(flag))
738
763
  throw new Error(`Unknown operation inspect option ${flag}`);
739
764
  if (!value || value.startsWith('--'))
740
765
  throw new Error(`Operation inspect option ${flag} needs a value`);
@@ -743,11 +768,11 @@ try {
743
768
  filters[name] = value;
744
769
  }
745
770
  const manifest = await compile(hasConfig ? rest[1] : 'docs.config.yaml');
746
- const matches = (manifest.operations[rest[0]] ?? []).filter(item => (!filters.channel || item.channel === filters.channel) && (!filters.version || item.version === filters.version) && (!filters.language || item.language === filters.language));
771
+ const matches = (manifest.operations[rest[0]] ?? []).filter(item => (!filters.product || item.product === filters.product) && (!filters.channel || item.channel === filters.channel) && (!filters.version || item.version === filters.version) && (!filters.language || item.language === filters.language));
747
772
  process.stdout.write(JSON.stringify({ status: matches.length ? 'ok' : 'missing-variant', operationId: rest[0], bindings: matches }, null, 2) + '\n');
748
773
  }
749
774
  else {
750
- throw new Error('Usage: shoalrun init [directory] [--starter minimal|api-docs|showcase] | build [config] [output] [--source-commit SHA] [--release-label LABEL] | check [config] [--json] | audit [config] | vercel build [config] [output] [--source-commit SHA] [--release-label LABEL] [--chat] | serve <site-directory> [--host HOST] [--port PORT] [--search [--config FILE]] [--ask [--config FILE] [--model MODEL] [--reader-view FACET=CHOICE[,CHOICE]]...] | search <site-directory> <query> [--channel C --version V --language L --limit N] | answers <site-directory> --questions FILE [--config FILE] [--model MODEL] [--reader-view FACET=CHOICE[,CHOICE]]... | chat pause|resume|status --config FILE | ask-log <log-file> [--min-repeats N] [--limit N] [--cards-out FILE] [--json] | ask <site-directory> "<question>" [--config FILE] [--model MODEL] [--passages N] [--reader-view FACET=CHOICE[,CHOICE]]... [--channel C --version V --language L] [--no-rerank] [--no-direct] [--no-escalate] [--no-cards] [--json] | eval prepare <site-directory> --tasks FILE --out REPORT | eval check <site-directory> --tasks FILE --report REPORT | index <site-directory> [--embed [--config FILE] [--provider voyage|openai] [--model MODEL] [--dimension N] [--base-url URL] [--key-env NAME]] | ingredient draft --spec FILE --out FILE [--config FILE] [--check] | recipe draft --spec FILE --out FILE [--config FILE] [--check] | scaffold <template> -n <target> [--config FILE] [--id ID] [--title TITLE] [--summary SUMMARY] [--slug SLUG] [--channel C] [--version V] [--language L] [--operation ID]... | scaffold <template> <config> <target> --id ID --title TITLE --summary SUMMARY --slug SLUG | config validate|resolve|graph <config> | config explain <key> <config> | operation inspect <id> <config> [--channel C --version V --language L] | api audit <openapi-file> | api focused-audit <site-directory> | api review <config-file> --output <local-directory> | api select <api-id> <config> --output <selection.yaml> | api materialize <api-id> <config> (--all | --operation ID | --route "METHOD /path")... [--output content/subdirectory]');
775
+ throw new Error('Usage: shoalrun init [directory] [--starter minimal|api-docs|showcase] | build [config] [output] [--source-commit SHA] [--release-label LABEL] | check [config] [--json] | audit [config] | vercel build [config] [output] [--source-commit SHA] [--release-label LABEL] [--chat] | serve <site-directory> [--host HOST] [--port PORT] [--search [--config FILE]] [--ask [--config FILE] [--model MODEL] [--reader-view FACET=CHOICE[,CHOICE]]...] | search <site-directory> <query> [--product P] [--channel C --version V --language L --limit N] | answers <site-directory> --questions FILE [--config FILE] [--model MODEL] [--reader-view FACET=CHOICE[,CHOICE]]... | chat pause|resume|status --config FILE | ask-log <log-file> [--min-repeats N] [--limit N] [--cards-out FILE] [--json] | ask <site-directory> "<question>" [--config FILE] [--model MODEL] [--passages N] [--reader-view FACET=CHOICE[,CHOICE]]... [--product P] [--channel C --version V --language L] [--no-rerank] [--no-direct] [--no-escalate] [--no-cards] [--json] | eval prepare <site-directory> --tasks FILE --out REPORT | eval check <site-directory> --tasks FILE --report REPORT | index <site-directory> [--embed [--config FILE] [--provider voyage|openai] [--model MODEL] [--dimension N] [--base-url URL] [--key-env NAME]] | ingredient draft --spec FILE --out FILE [--config FILE] [--check] | recipe draft --spec FILE --out FILE [--config FILE] [--check] | scaffold <template> -n <target> [--config FILE] [--id ID] [--title TITLE] [--summary SUMMARY] [--slug SLUG] [--product P] [--channel C] [--version V] [--language L] [--operation ID]... | scaffold <template> <config> <target> --id ID --title TITLE --summary SUMMARY --slug SLUG | config validate|resolve|graph <config> | config explain <key> <config> | operation inspect <id> <config> [--product P] [--channel C --version V --language L] | api audit <openapi-file> | api focused-audit <site-directory> | api review <config-file> --output <local-directory> | api select <api-id> <config> --output <selection.yaml> | api materialize <api-id> <config> (--all | --operation ID | --route "METHOD /path")... [--output content/subdirectory]');
751
776
  }
752
777
  }
753
778
  catch (error) {
@@ -39,6 +39,14 @@ export interface CompilerSiteConfig extends ConfigMapping {
39
39
  basePath?: unknown;
40
40
  contentDir?: string;
41
41
  }
42
+ export type ProductPublicationConfig = {
43
+ label?: string;
44
+ pathPrefix: string;
45
+ defaultVersion: string;
46
+ versions: Record<string, {
47
+ pathPrefix?: string;
48
+ }>;
49
+ };
42
50
  export interface CompilerPublicationsConfig extends ConfigMapping {
43
51
  channels: Record<string, {
44
52
  pathPrefix?: string;
@@ -46,7 +54,9 @@ export interface CompilerPublicationsConfig extends ConfigMapping {
46
54
  versions: Record<string, {
47
55
  pathPrefix?: string;
48
56
  }>;
57
+ products?: Record<string, ProductPublicationConfig>;
49
58
  defaults?: {
59
+ product?: string;
50
60
  channel?: string;
51
61
  version?: string;
52
62
  language?: string;
@@ -66,3 +76,10 @@ export declare function navigationCounts(outputs: unknown): boolean;
66
76
  */
67
77
  export declare function requireSiteSection(config: ResolvedCompilerConfig): CompilerSiteConfig;
68
78
  export declare function requirePublicationsSection(config: ResolvedCompilerConfig): CompilerPublicationsConfig;
79
+ /** Resolve product-local defaults without borrowing another product's catalog. */
80
+ export declare function resolvePublication(publications: CompilerPublicationsConfig, value: Record<string, unknown>, language?: string): {
81
+ product?: string;
82
+ channel: string;
83
+ version: string;
84
+ language: string;
85
+ };
@@ -58,12 +58,13 @@ export function requireSiteSection(config) {
58
58
  }
59
59
  export function requirePublicationsSection(config) {
60
60
  const publications = config.publications;
61
- if (!isConfigMapping(publications) || !isConfigMapping(publications.channels) || !isConfigMapping(publications.versions)) {
61
+ if (!isConfigMapping(publications) || !isConfigMapping(publications.channels) || (publications.versions !== undefined && !isConfigMapping(publications.versions)) || (publications.versions === undefined && !isConfigMapping(publications.products))) {
62
62
  throw new Error('publications needs channels and versions mappings');
63
63
  }
64
64
  if (publications.defaults !== undefined && !isConfigMapping(publications.defaults)) {
65
65
  throw new Error('publications.defaults must be a mapping of channel, version, and language');
66
66
  }
67
+ publications.versions ??= {};
67
68
  for (const group of ['channels', 'versions']) {
68
69
  for (const [name, value] of Object.entries(publications[group])) {
69
70
  if (!isConfigMapping(value) || (value.pathPrefix !== undefined && typeof value.pathPrefix !== 'string')) {
@@ -72,8 +73,48 @@ export function requirePublicationsSection(config) {
72
73
  }
73
74
  }
74
75
  const defaults = publications.defaults;
75
- if (isConfigMapping(defaults) && ['channel', 'version', 'language'].some(key => defaults[key] !== undefined && typeof defaults[key] !== 'string')) {
76
+ if (isConfigMapping(defaults) && ['product', 'channel', 'version', 'language'].some(key => defaults[key] !== undefined && typeof defaults[key] !== 'string')) {
76
77
  throw new Error('publications.defaults must be a mapping of channel, version, and language');
77
78
  }
79
+ if (publications.products !== undefined) {
80
+ if (!isConfigMapping(publications.products) || !Object.keys(publications.products).length)
81
+ throw new Error('publications.products must be a nonempty mapping');
82
+ const prefixes = new Set();
83
+ for (const [id, product] of Object.entries(publications.products)) {
84
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id) || !isConfigMapping(product) || Object.keys(product).some(key => !['label', 'pathPrefix', 'defaultVersion', 'versions'].includes(key)))
85
+ throw new Error(`Invalid publication product ${id}`);
86
+ if (typeof product.pathPrefix !== 'string' || !/^\/[A-Za-z0-9/_-]+$/.test(product.pathPrefix) || product.pathPrefix.endsWith('/') || product.pathPrefix.includes('//') || product.pathPrefix.includes('..'))
87
+ throw new Error(`Product ${id} needs an absolute nonempty pathPrefix without a trailing slash`);
88
+ if (prefixes.has(product.pathPrefix.toLowerCase()))
89
+ throw new Error(`Duplicate product pathPrefix ${product.pathPrefix}`);
90
+ prefixes.add(product.pathPrefix.toLowerCase());
91
+ if (product.label !== undefined && (typeof product.label !== 'string' || !product.label.trim()))
92
+ throw new Error(`Product ${id}.label must be nonempty text`);
93
+ if (!isConfigMapping(product.versions) || !Object.keys(product.versions).length || typeof product.defaultVersion !== 'string' || !Object.hasOwn(product.versions, product.defaultVersion))
94
+ throw new Error(`Product ${id} needs versions and a valid defaultVersion`);
95
+ const versionPrefixes = new Set();
96
+ for (const [version, definition] of Object.entries(product.versions)) {
97
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(version) || !isConfigMapping(definition) || (definition.pathPrefix !== undefined && (typeof definition.pathPrefix !== 'string' || (definition.pathPrefix !== '' && (!/^\/[A-Za-z0-9/_-]+$/.test(definition.pathPrefix) || definition.pathPrefix.includes('//') || definition.pathPrefix.endsWith('/'))))))
98
+ throw new Error(`Product ${id} has invalid version ${version}`);
99
+ const prefix = String(definition.pathPrefix ?? '').toLowerCase();
100
+ if (versionPrefixes.has(prefix))
101
+ throw new Error(`Product ${id} has duplicate version pathPrefix ${prefix || '(empty)'}`);
102
+ versionPrefixes.add(prefix);
103
+ }
104
+ }
105
+ }
78
106
  return publications;
79
107
  }
108
+ /** Resolve product-local defaults without borrowing another product's catalog. */
109
+ export function resolvePublication(publications, value, language = 'en') {
110
+ const product = value.product;
111
+ if (product !== undefined && (typeof product !== 'string' || !publications.products || !Object.hasOwn(publications.products, product)))
112
+ throw new Error(`Unknown publication product ${String(product)}`);
113
+ const catalog = product === undefined ? publications.versions ?? {} : publications.products[product].versions;
114
+ const scopedDefault = product !== undefined && publications.defaults?.product === product && publications.defaults.version && Object.hasOwn(catalog, publications.defaults.version) ? publications.defaults.version : undefined;
115
+ const version = value.version ?? (product === undefined ? publications.defaults?.version : scopedDefault ?? publications.products[product].defaultVersion);
116
+ const channel = value.channel ?? publications.defaults?.channel;
117
+ if (typeof channel !== 'string' || !Object.hasOwn(publications.channels, channel) || typeof version !== 'string' || !Object.hasOwn(catalog, version) || (value.language !== undefined && (typeof value.language !== 'string' || !value.language)))
118
+ throw new Error(`Unknown publication ${product === undefined ? '' : String(product) + '/'}${String(channel)}/${String(version)}`);
119
+ return { ...(product === undefined ? {} : { product: product }), channel, version, language: value.language ?? language };
120
+ }
@@ -11,6 +11,7 @@ export declare function compile(configFile: string, destination?: string, proven
11
11
  sourceOverrides?: ReadonlyMap<string, string>;
12
12
  authoringFiles?: ReadonlySet<string>;
13
13
  profile?: string;
14
+ onDependency?: (file: string) => void;
14
15
  }): Promise<{
15
16
  authoringSources?: {
16
17
  id: string;
@@ -93,6 +94,10 @@ export declare function compile(configFile: string, destination?: string, proven
93
94
  url?: string;
94
95
  }[];
95
96
  verified?: string | undefined;
97
+ availability?: {
98
+ since?: string;
99
+ through?: string;
100
+ } | undefined;
96
101
  updated?: string | undefined;
97
102
  indexable: boolean;
98
103
  navigationTab: {
@@ -158,6 +163,10 @@ export declare function compile(configFile: string, destination?: string, proven
158
163
  url?: string;
159
164
  }[];
160
165
  verified?: string | undefined;
166
+ availability?: {
167
+ since?: string;
168
+ through?: string;
169
+ } | undefined;
161
170
  updated?: string | undefined;
162
171
  indexable: boolean;
163
172
  navigationTab?: undefined;
@@ -176,6 +185,7 @@ export declare function compile(configFile: string, destination?: string, proven
176
185
  operations: Record<string, {
177
186
  id: string;
178
187
  type: string;
188
+ product?: string;
179
189
  channel: string;
180
190
  version: string;
181
191
  language: string;
@@ -195,6 +205,7 @@ export declare function compile(configFile: string, destination?: string, proven
195
205
  }[];
196
206
  apiSources: {
197
207
  apiId: string;
208
+ product?: string;
198
209
  channel: string;
199
210
  version: string;
200
211
  endpoint: string | null;
@@ -216,6 +227,16 @@ export declare function compile(configFile: string, destination?: string, proven
216
227
  sitemap?: string | undefined;
217
228
  basePath: string;
218
229
  searchSynonyms?: unknown[] | undefined;
230
+ publications?: {
231
+ enabled: Variant[];
232
+ products: {
233
+ [k: string]: {
234
+ versions: string[];
235
+ defaultVersion?: string | undefined;
236
+ label?: string | undefined;
237
+ };
238
+ };
239
+ } | undefined;
219
240
  schemaVersion: number;
220
241
  configDigest: string;
221
242
  }>;
package/dist/compiler.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { documentKey, publicationKey, samePublication } from './publication-identity.js';
1
2
  import { validateHeader, validateFooter } from './site-identity.js';
2
3
  import { profileSelection } from './deployment-profile.js';
3
4
  import { profileNavigation } from './project-navigation.js';
@@ -43,14 +44,14 @@ import { assembleArtifacts } from './artifact-bundle.js';
43
44
  import { materializePages } from './page-materialization.js';
44
45
  import { renderPublicationPages } from './publication-render.js';
45
46
  import { buildPublicationManifest } from './publication-manifest.js';
46
- import { configField, isConfigMapping, requirePublicationsSection, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
47
+ import { configField, isConfigMapping, requirePublicationsSection, resolvePublication, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
47
48
  import { validateRetrieval } from './retrieval-config.js';
48
49
  import { validateChat } from './chat-config.js';
49
50
  import { normalizeBasePath, sitePath } from './site-path.js';
50
51
  const generatedReferenceBody = 'This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context.\n';
51
52
  const generatedWebhookBody = 'This webhook reference is generated from the OpenAPI description. The provider sends this event to the receiver.\n';
52
53
  const digest = (value) => createHash('sha256').update(value).digest('hex');
53
- const keyFor = (id, variant) => `${id}|${variant.channel}|${variant.version}|${variant.language}`;
54
+ const keyFor = documentKey;
54
55
  function validateSearch(value, declaringFile) {
55
56
  if (value === undefined)
56
57
  return { provider: 'lexical', module: builtInSearchProvider, index: true };
@@ -101,7 +102,7 @@ export async function checkThemeContrast(configFile) {
101
102
  return { modes, palette: palette.name };
102
103
  }
103
104
  export async function compile(configFile, destination, provenance = {}, options = {}) {
104
- const loaded = await loadConfig(configFile, { profile: options.profile });
105
+ const loaded = await loadConfig(configFile, { profile: options.profile, onDependency: options.onDependency });
105
106
  const componentPlugins = await loadComponentPlugins(loaded);
106
107
  const provenanceRecord = buildInfo(loaded.digest, provenance);
107
108
  const resolvedConfig = resolvedCompilerConfig(loaded.value);
@@ -215,10 +216,12 @@ export async function compile(configFile, destination, provenance = {}, options
215
216
  if (!Array.isArray(enabledVariants))
216
217
  throw new Error('publications.enabled must declare at least one variant');
217
218
  const variants = enabledVariants.map((variant) => {
218
- if (!isConfigMapping(variant) || typeof variant.channel !== 'string' || typeof variant.version !== 'string' || (variant.language !== undefined && typeof variant.language !== 'string'))
219
- throw new Error('publications.enabled needs channel, version, and optional language');
220
- return { ...variant, channel: variant.channel, version: variant.version, language: variant.language ?? language };
219
+ if (!isConfigMapping(variant))
220
+ throw new Error('publications.enabled needs publication coordinates');
221
+ return resolvePublication(config.publications, variant, language);
221
222
  });
223
+ if (new Set(variants.map(publicationKey)).size !== variants.length)
224
+ throw new Error('publications.enabled has duplicate publication coordinates');
222
225
  if (!variants.length)
223
226
  throw new Error('publications.enabled must declare at least one variant');
224
227
  const externalSites = config.publications.externalSites ?? [];
@@ -263,7 +266,7 @@ export async function compile(configFile, destination, provenance = {}, options
263
266
  const document = isConfigMapping(rawDocument) ? rawDocument : {};
264
267
  const rawVariant = document.variant;
265
268
  const route = document.url;
266
- if (typeof document.id !== 'string' || !document.id || !isConfigMapping(rawVariant) || ['channel', 'version', 'language'].some(field => typeof rawVariant[field] !== 'string' || !rawVariant[field]) || typeof route !== 'string' || !route.startsWith('/') || route.startsWith('//') || route.includes('..') || /[?#\\]|%2f|%5c/i.test(route)) {
269
+ if (typeof document.id !== 'string' || !document.id || !isConfigMapping(rawVariant) || (rawVariant.product !== undefined && (typeof rawVariant.product !== 'string' || !rawVariant.product)) || ['channel', 'version', 'language'].some(field => typeof rawVariant[field] !== 'string' || !rawVariant[field]) || typeof route !== 'string' || !route.startsWith('/') || route.startsWith('//') || route.includes('..') || /[?#\\]|%2f|%5c/i.test(route)) {
267
270
  throw new Error(`${setting}.manifest has an invalid document identity, publication, or URL`);
268
271
  }
269
272
  const variant = rawVariant;
@@ -283,8 +286,8 @@ export async function compile(configFile, destination, provenance = {}, options
283
286
  if (editionBadge !== 'auto' && editionBadge !== 'always' && editionBadge !== 'never')
284
287
  throw new Error('site.editionBadge must be auto, always, or never');
285
288
  const varying = (field) => new Set(variants.map(variant => variant[field])).size > 1;
286
- const editionLabel = (variant) => editionBadge === 'never' ? '' : ['channel', 'version', 'language']
287
- .filter(field => editionBadge === 'always' || varying(field)).map(field => variant[field]).join(' · ');
289
+ const editionLabel = (variant) => editionBadge === 'never' ? '' : ['product', 'channel', 'version', 'language']
290
+ .filter(field => variant[field] !== undefined && (editionBadge === 'always' || varying(field))).map(field => variant[field]).join(' · ');
288
291
  const { docs, knownDocumentIds, knownDocumentTypes, routeOwners, contentDir, snippets, apiPlan, api, sourceForVariant, knownOperations, relatedApiTargets, guidesByApi, sourceForOperation } = await prepareContentWorkspace({
289
292
  base, basePath, config, loaded, variants, language, readerFilters, contentFilter, metadataProvider, metadataDependencies,
290
293
  sourceOverrides: options.sourceOverrides, authoringFiles: options.authoringFiles
@@ -390,7 +393,7 @@ export async function compile(configFile, destination, provenance = {}, options
390
393
  ] : [];
391
394
  for (const [operationId, bindings] of Object.entries(operations)) {
392
395
  for (const variant of variants) {
393
- const inVariant = bindings.filter(b => b.channel === variant.channel && b.version === variant.version && b.language === variant.language);
396
+ const inVariant = bindings.filter(b => samePublication(b, variant));
394
397
  if (inVariant.filter(b => b.type === 'api-reference').length > 1)
395
398
  throw new Error(`Multiple canonical references for ${operationId}`);
396
399
  }
@@ -414,7 +417,7 @@ export async function compile(configFile, destination, provenance = {}, options
414
417
  const to = rule.to;
415
418
  if (!isConfigMapping(to) || typeof to.doc !== 'string' || !to.doc || typeof to.channel !== 'string' || !to.channel || typeof to.version !== 'string' || !to.version || typeof to.language !== 'string' || !to.language)
416
419
  throw new Error(`Redirect ${rule.from} needs an explicit target variant`);
417
- const target = docs.get(keyFor(to.doc, { channel: to.channel, version: to.version, language: to.language }));
420
+ const target = docs.get(keyFor(to.doc, { channel: to.channel, version: to.version, language: to.language, ...(to.product === undefined ? {} : { product: String(to.product) }) }));
418
421
  if (!target)
419
422
  throw new Error(`Redirect ${rule.from} targets missing document variant`);
420
423
  const status = rule.status ?? 308;
@@ -423,7 +426,7 @@ export async function compile(configFile, destination, provenance = {}, options
423
426
  // The old page's Markdown twin moves too, so its .md URL redirects to the target's twin.
424
427
  redirects.push({ from: sourceRoute, to: target.route, markdownFrom: markdownRoute(sourceRoute.replace(/(.)\/+$/, '$1'), basePath), markdownTo: target.markdownRoute, status });
425
428
  }
426
- const apiSources = [...apiPublications.values()].map(({ apiId, variant, endpoint, referenceUrl, sourceUrl, mediaType }) => ({ apiId, channel: variant.channel, version: variant.version, endpoint: endpoint ?? null, referenceUrl, sourceUrl, mediaType }));
429
+ const apiSources = [...apiPublications.values()].map(({ apiId, variant, endpoint, referenceUrl, sourceUrl, mediaType }) => ({ apiId, ...(variant.product === undefined ? {} : { product: variant.product }), channel: variant.channel, version: variant.version, endpoint: endpoint ?? null, referenceUrl, sourceUrl, mediaType }));
427
430
  let catalog = null;
428
431
  const discoverable = apiSources.filter(item => item.endpoint);
429
432
  if (discoverable.length) {
@@ -442,6 +445,7 @@ export async function compile(configFile, destination, provenance = {}, options
442
445
  const manifestDependencies = [...new Set([...loaded.dependencies, ...componentPlugins.dependencies, ...externalManifestFiles, ...api.dependencies, ...(metadataProvider ? [metadataProvider.module] : []), ...metadataDependencies, ...(highlighter.dependency ? [highlighter.dependency] : []), ...styleFiles, ...(themeStyleFile ? [themeStyleFile] : []), ...palette.files, ...(search.module ? [search.module] : []), ...previewFiles, ...(customStyleFile ? [customStyleFile] : []), ...(customReaderModule ? [customReaderModule] : []), ...(analyticsModule ? [analyticsModule] : []), ...(mcpAnalyticsModule ? [mcpAnalyticsModule] : []), ...(shareImages.template ? [shareImages.template] : []), ...shareImages.fonts, ...(faviconFile ? [faviconFile] : []), ...heroImages.values(), ...walkthroughSources, ...fontFiles, ...fonts.faces.map(face => face.file), ...scriptFiles, iconLicenseFile, ...[...snippets.values()].map(s => s.file), ...[...docs.values()].map(d => d.file)])].sort();
443
446
  const llmsDiscovery = resolveLlmsDiscovery(configField(config.outputs, 'llms'));
444
447
  const { manifest, headers, sitemaps } = buildPublicationManifest({
448
+ configPublications: config.publications,
445
449
  fictionalDocuments: new Set(rendered.filter(({ doc }) => fictionalDocument(doc, llmsDiscovery)).map(({ doc }) => doc)),
446
450
  configDigest: loaded.digest, synonyms, basePath, publicPath, readerFilters, taxonomy: resolveTaxonomy(configField(config.frontmatter, 'taxonomy')), dependencies: manifestDependencies,
447
451
  rendered, resolvedNavigation, cardUses, snippetUses, apiEmbedUses, focusedContracts, operations,
@@ -1,10 +1,8 @@
1
+ import type { CompilerPublicationsConfig } from './compiler-config.js';
1
2
  import { type ComponentRegistry } from './component-plugins.js';
2
3
  import { type CalloutTypes } from './callouts.js';
3
4
  import { type BadgeVariants } from './badges.js';
4
5
  import { SnippetDefinition, SnippetUse } from './snippets.js';
5
6
  import { type ReaderFiltersConfig } from './reader-filters.js';
6
7
  import type { Document } from './content-source.js';
7
- export declare function transformMdx(tree: unknown, current: Document, registry: Map<string, Document>, snippets?: Map<string, SnippetDefinition>, projectValues?: Record<string, unknown>, uses?: SnippetUse[], calloutTypes?: CalloutTypes, projectRoot?: string, readerConfig?: ReaderFiltersConfig, frontmatterConfig?: unknown, publicationConfig?: {
8
- channels: Record<string, unknown>;
9
- versions: Record<string, unknown>;
10
- }, badgeVariants?: BadgeVariants, componentPlugins?: ComponentRegistry): unknown;
8
+ export declare function transformMdx(tree: unknown, current: Document, registry: Map<string, Document>, snippets?: Map<string, SnippetDefinition>, projectValues?: Record<string, unknown>, uses?: SnippetUse[], calloutTypes?: CalloutTypes, projectRoot?: string, readerConfig?: ReaderFiltersConfig, frontmatterConfig?: unknown, publicationConfig?: CompilerPublicationsConfig, badgeVariants?: BadgeVariants, componentPlugins?: ComponentRegistry, publicationRegistry?: Map<string, Document>): unknown;
@@ -1,3 +1,4 @@
1
+ import { documentKey } from './publication-identity.js';
1
2
  import { pruneFeatureTree } from './deployment-profile.js';
2
3
  import { lowerComponent } from './component-plugins.js';
3
4
  import { cardComponent } from './cards.js';
@@ -57,7 +58,7 @@ function isMdxAttribute(value) {
57
58
  function literalAttributes(attributes) {
58
59
  return attributes.every(item => item.type === 'mdxJsxAttribute' && typeof item.value === 'string');
59
60
  }
60
- export function transformMdx(tree, current, registry, snippets = new Map(), projectValues = {}, uses = [], calloutTypes = resolveCalloutTypes(undefined, current.file), projectRoot, readerConfig, frontmatterConfig = {}, publicationConfig, badgeVariants = resolveBadgeVariants(undefined, current.file), componentPlugins = new Map()) {
61
+ export function transformMdx(tree, current, registry, snippets = new Map(), projectValues = {}, uses = [], calloutTypes = resolveCalloutTypes(undefined, current.file), projectRoot, readerConfig, frontmatterConfig = {}, publicationConfig, badgeVariants = resolveBadgeVariants(undefined, current.file), componentPlugins = new Map(), publicationRegistry) {
61
62
  if (!isMdxRoot(tree))
62
63
  throw new Error(`${current.file}: parsed content must be a root with children`);
63
64
  tree = lowerSectionMarkers(pruneFeatureTree(tree, current.featureContext, current.file), current.file);
@@ -138,14 +139,18 @@ export function transformMdx(tree, current, registry, snippets = new Map(), proj
138
139
  }
139
140
  if (node.name === 'ForPublication') {
140
141
  const attributes = node.attributes ?? [];
141
- const allowed = ['channel', 'version', 'language'];
142
+ const allowed = ['product', 'channel', 'version', 'language'];
142
143
  if (node.type !== 'mdxJsxFlowElement' || !node.children?.length || !attributes.length || !literalAttributes(attributes) || attributes.some((item) => !allowed.includes(item.name) || !item.value.trim()) || new Set(attributes.map((item) => item.name)).size !== attributes.length) {
143
144
  throw new Error(`${sourceFile}: <ForPublication> needs block content and distinct literal channel, version, or language attributes`);
144
145
  }
145
- for (const item of attributes)
146
- if ((item.name === 'channel' || item.name === 'version') && publicationConfig && !Object.hasOwn(publicationConfig[item.name === 'channel' ? 'channels' : 'versions'], item.value)) {
146
+ const product = attributes.find(item => item.name === 'product')?.value ?? current.variant.product;
147
+ for (const item of attributes) {
148
+ const catalog = item.name === 'product' ? publicationConfig?.products
149
+ : item.name === 'channel' ? publicationConfig?.channels
150
+ : item.name === 'version' ? (product ? publicationConfig?.products?.[product]?.versions : publicationConfig?.versions) : undefined;
151
+ if (publicationConfig && item.name !== 'language' && (!catalog || !Object.hasOwn(catalog, item.value)))
147
152
  throw new Error(`${sourceFile}: <ForPublication> names unknown ${item.name} ${item.value}`);
148
- }
153
+ }
149
154
  if (attributes.some((item) => current.variant[item.name] !== item.value))
150
155
  return [];
151
156
  return childrenOf(node.children, scope, stack, sourceFile);
@@ -635,9 +640,17 @@ export function transformMdx(tree, current, registry, snippets = new Map(), proj
635
640
  return text(String(scope[name]));
636
641
  }
637
642
  if (node.name === 'DocLink') {
638
- const target = registry.get(attr(node, 'doc'));
643
+ const attributes = node.attributes ?? [];
644
+ if (!literalAttributes(attributes) || attributes.some(item => !['doc', 'product', 'channel', 'version', 'language'].includes(item.name)) || new Set(attributes.map(item => item.name)).size !== attributes.length)
645
+ throw new Error(`${sourceFile}: DocLink needs distinct literal publication attributes`);
646
+ const id = attr(node, 'doc');
647
+ const qualified = attributes.some(item => item.name !== 'doc');
648
+ if (qualified && attributes.some(item => item.name === 'product' && item.value !== current.variant.product) && !attributes.some(item => item.name === 'version'))
649
+ throw new Error(`${sourceFile}: cross-product DocLink needs an explicit version`);
650
+ const variant = { ...current.variant, ...Object.fromEntries(attributes.filter(item => item.name !== 'doc').map(item => [item.name, item.value])) };
651
+ const target = qualified ? publicationRegistry?.get(documentKey(id, variant)) : registry.get(id);
639
652
  if (!target)
640
- throw new Error(`${sourceFile}: unknown DocLink target`);
653
+ throw new Error(`${sourceFile}: unknown DocLink target ${id} in selected publication`);
641
654
  return link(target.route, (node.children ?? []).map((x) => x.value ?? '').join('') || target.frontmatter.title);
642
655
  }
643
656
  if (node.name === 'Callout') {
package/dist/config.d.ts CHANGED
@@ -10,6 +10,7 @@ export declare class ConfigError extends Error {
10
10
  }
11
11
  export declare function loadConfig(file: string, options?: {
12
12
  profile?: string;
13
+ onDependency?: (file: string) => void;
13
14
  }): Promise<{
14
15
  value: Record<string, unknown>;
15
16
  tree: Tree;
package/dist/config.js CHANGED
@@ -68,6 +68,7 @@ export async function loadConfig(file, options = {}) {
68
68
  if (stack.includes(current))
69
69
  throw new ConfigError(`Configuration cycle: ${[...stack, current].join(' -> ')}`);
70
70
  dependencies.add(current);
71
+ options.onDependency?.(current);
71
72
  const raw = await readFile(current, 'utf8');
72
73
  let parsed;
73
74
  try {
@@ -121,7 +122,7 @@ export async function loadConfig(file, options = {}) {
121
122
  const raw = value;
122
123
  const profileSettings = treeObject(tree.value) ? tree.value.profiles : undefined;
123
124
  const manifestNode = profileSettings && treeObject(profileSettings.value) ? profileSettings.value.manifest : undefined;
124
- const deployment = await resolveDeploymentProfile(raw.profiles, raw, manifestNode?.source.file ?? root, options.profile);
125
+ const deployment = await resolveDeploymentProfile(raw.profiles, raw, manifestNode?.source.file ?? root, options.profile, options.onDependency);
125
126
  if (deployment) {
126
127
  for (const file of deployment.dependencies)
127
128
  dependencies.add(file);
@@ -3,6 +3,7 @@ export type ContentPublication = {
3
3
  channel: string;
4
4
  version: string;
5
5
  language: string;
6
+ product?: string;
6
7
  };
7
8
  export type ContentFormat = 'html' | 'markdown';
8
9
  export type ContentRef = {
@@ -62,7 +63,7 @@ export type ContentResource = {
62
63
  }>;
63
64
  };
64
65
  export type ContentManifest = {
65
- schemaVersion: 1;
66
+ schemaVersion: 1 | 2;
66
67
  kind: 'shoalrun-content-export';
67
68
  digest: string;
68
69
  publicBase: string;
@@ -1,6 +1,6 @@
1
- import type { ContentManifest, ContentRef } from './content-delivery-contract.js';
1
+ import type { ContentManifest, ContentRef, ContentPublication } from './content-delivery-contract.js';
2
2
  export declare const safeContentPath: (value: any) => value is string;
3
- export declare const validContentPublication: (value: any) => boolean;
3
+ export declare const validContentPublication: (value: any) => value is ContentPublication;
4
4
  export declare function validContentRef(value: any): value is ContentRef;
5
5
  export declare function validateContentManifest(value: any, maxResources?: number, maxResourceBytes?: number): asserts value is ContentManifest;
6
6
  /** Shared metadata validation; transport supplies its file/asset inventory policy. */