@shoalrun/cli 0.1.0-alpha.11 → 0.1.0-alpha.13

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 (602) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +59 -17
  3. package/agent-docs/.well-known/shoalrun/navigation/examples-tab-50f26fe22670.txt +22 -0
  4. package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +33 -3
  5. package/agent-docs/.well-known/shoalrun/navigation/reference-tab-50f26fe22670.txt +22 -0
  6. package/agent-docs/SNAPSHOT.json +5 -5
  7. package/agent-docs/api-docs/focused-contracts.md +2 -2
  8. package/agent-docs/api-docs/generate.md +6 -6
  9. package/agent-docs/api-docs/generate.sections/add-useful-examples.md +2 -2
  10. package/agent-docs/api-docs/generate.sections/choose-generated-references-or-mdx.md +5 -5
  11. package/agent-docs/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +2 -2
  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 +2 -2
  14. package/agent-docs/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md +2 -2
  15. package/agent-docs/api-docs/generate.sections/override-generated-reference-order-in-navigation.md +3 -3
  16. package/agent-docs/api-docs/generate.sections/related-reading.md +2 -2
  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 +14 -13
  19. package/agent-docs/author/add-page.md +8 -6
  20. package/agent-docs/author/agent-overview.md +1 -1
  21. package/agent-docs/author/agent-workflow.md +1 -1
  22. package/agent-docs/author/analytics.md +1 -1
  23. package/agent-docs/author/analytics.sections/adapter-exports-and-consent.md +1 -1
  24. package/agent-docs/author/analytics.sections/built-in-events.md +1 -1
  25. package/agent-docs/author/analytics.sections/configure-an-adapter.md +1 -1
  26. package/agent-docs/author/analytics.sections/custom-interactions.md +1 -1
  27. package/agent-docs/author/analytics.sections/event-format.md +1 -1
  28. package/agent-docs/author/analytics.sections/html-markdown-and-agents.md +1 -1
  29. package/agent-docs/author/analytics.sections/inspect-events-locally.md +1 -1
  30. package/agent-docs/author/analytics.sections/map-events-to-your-service.md +1 -1
  31. package/agent-docs/author/analytics.sections/posthog-example.md +1 -1
  32. package/agent-docs/author/analytics.sections/related-reading.md +1 -1
  33. package/agent-docs/author/authoring-agent.md +1 -1
  34. package/agent-docs/author/coding-agent.md +1 -1
  35. package/agent-docs/author/components/action-link.md +9 -3
  36. package/agent-docs/author/components/api-embeds.md +11 -3
  37. package/agent-docs/author/components/api-embeds.sections/apiexample.md +7 -3
  38. package/agent-docs/author/components/api-embeds.sections/html-markdown-and-agents.md +3 -3
  39. package/agent-docs/author/components/api-embeds.sections/related-reading.md +3 -3
  40. package/agent-docs/author/components/badge.md +8 -4
  41. package/agent-docs/author/components/breadcrumbs.md +1 -1
  42. package/agent-docs/author/components/callout.md +8 -4
  43. package/agent-docs/author/components/cards.md +2 -2
  44. package/agent-docs/author/components/cards.sections/add-a-lucide-icon.md +2 -2
  45. package/agent-docs/author/components/cards.sections/build-a-collection.md +2 -2
  46. package/agent-docs/author/components/cards.sections/curate-a-reading-list.md +2 -2
  47. package/agent-docs/author/components/cards.sections/html-markdown-and-agents.md +2 -2
  48. package/agent-docs/author/components/cards.sections/link-to-one-document.md +2 -2
  49. package/agent-docs/author/components/cards.sections/override-card-text.md +2 -2
  50. package/agent-docs/author/components/cards.sections/related-reading.md +2 -2
  51. package/agent-docs/author/components/code-blocks.md +8 -4
  52. package/agent-docs/author/components/collapsible.md +7 -3
  53. package/agent-docs/author/components/cookbook-chooser.md +7 -3
  54. package/agent-docs/author/components/custom/react.md +1 -1
  55. package/agent-docs/author/components/custom/react.sections/html-markdown-and-agents.md +1 -1
  56. package/agent-docs/author/components/custom/react.sections/interactive-react-example.md +1 -1
  57. package/agent-docs/author/components/custom/react.sections/registration.md +1 -1
  58. package/agent-docs/author/components/custom/react.sections/related-reading.md +1 -1
  59. package/agent-docs/author/components/custom/react.sections/share-the-model-with-the-browser.md +1 -1
  60. package/agent-docs/author/components/custom/react.sections/where-the-content-lives.md +1 -1
  61. package/agent-docs/author/components/custom.md +1 -1
  62. package/agent-docs/author/components/definition-list.md +5 -3
  63. package/agent-docs/author/components/diagrams/d2-gallery.md +2 -2
  64. package/agent-docs/author/components/diagrams/d2-gallery.sections/basic-shapes.md +2 -2
  65. package/agent-docs/author/components/diagrams/d2-gallery.sections/flows-and-structures.md +2 -2
  66. package/agent-docs/author/components/diagrams/d2-gallery.sections/html-markdown-and-agents.md +2 -2
  67. package/agent-docs/author/components/diagrams/d2-gallery.sections/layout-engines.md +2 -2
  68. package/agent-docs/author/components/diagrams/d2-gallery.sections/related-reading.md +2 -2
  69. package/agent-docs/author/components/diagrams/d2-gallery.sections/sequences-and-grids.md +2 -2
  70. package/agent-docs/author/components/diagrams/d2-gallery.sections/styles-and-code.md +2 -2
  71. package/agent-docs/author/components/diagrams/pele-gallery.md +2 -2
  72. package/agent-docs/author/components/diagrams/pele-gallery.sections/charts-and-planning.md +2 -2
  73. package/agent-docs/author/components/diagrams/pele-gallery.sections/flowchart-shapes.md +2 -2
  74. package/agent-docs/author/components/diagrams/pele-gallery.sections/flows-and-behavior.md +2 -2
  75. package/agent-docs/author/components/diagrams/pele-gallery.sections/html-markdown-and-agents.md +2 -2
  76. package/agent-docs/author/components/diagrams/pele-gallery.sections/related-reading.md +2 -2
  77. package/agent-docs/author/components/diagrams/pele-gallery.sections/specialized-diagrams.md +2 -2
  78. package/agent-docs/author/components/diagrams/pele-gallery.sections/systems-and-structures.md +2 -2
  79. package/agent-docs/author/components/diagrams.md +13 -5
  80. package/agent-docs/author/components/doc-link.md +7 -3
  81. package/agent-docs/author/components/fields.md +6 -4
  82. package/agent-docs/author/components/file-tree.md +7 -3
  83. package/agent-docs/author/components/images.md +5 -3
  84. package/agent-docs/author/components/info-hint.md +7 -3
  85. package/agent-docs/author/components/kbd.md +5 -3
  86. package/agent-docs/author/components/math.md +7 -3
  87. package/agent-docs/author/components/only.md +9 -5
  88. package/agent-docs/author/components/progress.md +7 -3
  89. package/agent-docs/author/components/related-reading.md +7 -3
  90. package/agent-docs/author/components/steps.md +9 -3
  91. package/agent-docs/author/components/tables.md +7 -3
  92. package/agent-docs/author/components/tabs.md +7 -3
  93. package/agent-docs/author/components/timeline.md +10 -4
  94. package/agent-docs/author/components/tooltips.md +7 -3
  95. package/agent-docs/author/components/walkthroughs.md +5 -3
  96. package/agent-docs/author/components/walkthroughs.sections/attributes.md +3 -3
  97. package/agent-docs/author/components/walkthroughs.sections/build-up-code.md +3 -3
  98. package/agent-docs/author/components/walkthroughs.sections/choose-a-layout.md +3 -3
  99. package/agent-docs/author/components/walkthroughs.sections/explain-one-file.md +3 -3
  100. package/agent-docs/author/components/walkthroughs.sections/html-markdown-and-agents.md +3 -3
  101. package/agent-docs/author/components/walkthroughs.sections/related-reading.md +3 -3
  102. package/agent-docs/author/components/walkthroughs.sections/syntax.md +51 -0
  103. package/agent-docs/author/components/walkthroughs.sections/take-code-from-a-file.md +3 -22
  104. package/agent-docs/author/components.md +19 -4
  105. package/agent-docs/author/css.md +13 -10
  106. package/agent-docs/author/css.sections/borders-fields-and-navigation-tokens.md +3 -3
  107. package/agent-docs/author/css.sections/core-color-tokens.md +3 -3
  108. package/agent-docs/author/css.sections/html-markdown-and-agents.md +54 -0
  109. package/agent-docs/author/css.sections/page-attributes.md +9 -9
  110. package/agent-docs/author/css.sections/page-transitions.md +3 -3
  111. package/agent-docs/author/css.sections/responsive-behavior.md +3 -3
  112. package/agent-docs/author/css.sections/status-code-and-callout-tokens.md +3 -3
  113. package/agent-docs/author/css.sections/typography-shape-and-width-tokens.md +3 -3
  114. package/agent-docs/author/custom-metadata.md +2 -2
  115. package/agent-docs/author/custom-metadata.sections/add-a-custom-page-field.md +2 -2
  116. package/agent-docs/author/custom-metadata.sections/choose-text-for-each-surface.md +2 -2
  117. package/agent-docs/author/custom-metadata.sections/preview-changes-to-metadata-providers.md +2 -2
  118. package/agent-docs/author/custom-metadata.sections/read-metadata-from-a-project-module.md +2 -2
  119. package/agent-docs/author/custom-metadata.sections/related-reading.md +2 -2
  120. package/agent-docs/author/design-templates.md +1 -1
  121. package/agent-docs/author/design-writing-guides.md +1 -1
  122. package/agent-docs/author/frontmatter-reference.md +34 -27
  123. package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +5 -3
  124. package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +5 -3
  125. package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +5 -3
  126. package/agent-docs/author/frontmatter-reference.sections/html-markdown-and-agents.md +33 -0
  127. package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +5 -3
  128. package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +5 -3
  129. package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +5 -3
  130. package/agent-docs/author/frontmatter-reference.sections/related-reading.md +5 -3
  131. package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +5 -3
  132. package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +5 -3
  133. package/agent-docs/author/frontmatter.md +7 -4
  134. package/agent-docs/author/frontmatter.sections/audience-badges.md +3 -3
  135. package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +3 -3
  136. package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +3 -3
  137. package/agent-docs/author/frontmatter.sections/optional-native-fields.md +7 -4
  138. package/agent-docs/author/frontmatter.sections/publication-fields.md +3 -3
  139. package/agent-docs/author/frontmatter.sections/publishing-policy.md +3 -3
  140. package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +3 -3
  141. package/agent-docs/author/frontmatter.sections/related-reading.md +3 -3
  142. package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +3 -3
  143. package/agent-docs/author/frontmatter.sections/seo-fields.md +3 -3
  144. package/agent-docs/author/frontmatter.sections/validation-rules.md +3 -3
  145. package/agent-docs/author/markdown-metadata.md +17 -9
  146. package/agent-docs/author/navigation.md +13 -2
  147. package/agent-docs/author/navigation.sections/arrange-authored-pages.md +2 -2
  148. package/agent-docs/author/navigation.sections/fill-an-api-tag-group.md +2 -2
  149. package/agent-docs/author/navigation.sections/hide-group-page-counts.md +13 -2
  150. package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +2 -2
  151. package/agent-docs/author/navigation.sections/local-api-preview.md +2 -2
  152. package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +2 -2
  153. package/agent-docs/author/navigation.sections/optionally-split-a-large-menu-into-files.md +2 -2
  154. package/agent-docs/author/navigation.sections/reach-navigation-while-reading.md +2 -2
  155. package/agent-docs/author/navigation.sections/related-reading.md +2 -2
  156. package/agent-docs/author/navigation.sections/split-navigation-into-tabs.md +2 -2
  157. package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +2 -2
  158. package/agent-docs/author/recipe-drafts.md +16 -16
  159. package/agent-docs/author/recipe-drafts.sections/1-write-one-reusable-step.md +5 -5
  160. package/agent-docs/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md +3 -3
  161. package/agent-docs/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md +4 -4
  162. package/agent-docs/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md +3 -3
  163. package/agent-docs/author/recipe-drafts.sections/related-reading.md +1 -1
  164. package/agent-docs/author/recipe-drafts.sections/start-an-ingredient-from-an-api-example.md +5 -5
  165. package/agent-docs/author/recipes.md +4 -4
  166. package/agent-docs/author/recipes.sections/how-agents-use-this.md +1 -1
  167. package/agent-docs/author/recipes.sections/one-example-from-shoalrun.md +4 -4
  168. package/agent-docs/author/recipes.sections/related-reading.md +1 -1
  169. package/agent-docs/author/recipes.sections/try-a-complete-workflow.md +1 -1
  170. package/agent-docs/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md +1 -1
  171. package/agent-docs/author/recipes.sections/what-changing-an-ingredient-updates.md +1 -1
  172. package/agent-docs/author/recipes.sections/what-each-file-does.md +1 -1
  173. package/agent-docs/author/recipes.sections/what-happens-and-when.md +1 -1
  174. package/agent-docs/author/related-reading.md +5 -1
  175. package/agent-docs/author/related-reading.sections/automatic-footers.md +1 -1
  176. package/agent-docs/author/related-reading.sections/declare-relationships.md +1 -1
  177. package/agent-docs/author/related-reading.sections/display-related-documents.md +1 -1
  178. package/agent-docs/author/related-reading.sections/html-markdown-and-agents.md +28 -0
  179. package/agent-docs/author/related-reading.sections/inspect-output-and-changes.md +1 -1
  180. package/agent-docs/author/related-reading.sections/reading-paths-in-section-markdown.md +1 -1
  181. package/agent-docs/author/related-reading.sections/related-reading.md +1 -1
  182. package/agent-docs/author/related-reading.sections/where-relationship-explanations-come-from.md +1 -1
  183. package/agent-docs/author/search.md +1 -1
  184. package/agent-docs/author/search.sections/choose-a-provider.md +1 -1
  185. package/agent-docs/author/search.sections/cli-and-mcp-ranking-details.md +1 -1
  186. package/agent-docs/author/search.sections/hosted-semantic-search-limits.md +1 -1
  187. package/agent-docs/author/search.sections/html-markdown-and-agents.md +1 -1
  188. package/agent-docs/author/search.sections/lexical-search.md +1 -1
  189. package/agent-docs/author/search.sections/local-semantic-preview.md +1 -1
  190. package/agent-docs/author/search.sections/read-a-search-result-with-an-agent.md +1 -1
  191. package/agent-docs/author/search.sections/related-reading.md +1 -1
  192. package/agent-docs/author/search.sections/reuse-the-lexical-index.md +1 -1
  193. package/agent-docs/author/search.sections/turn-search-off.md +1 -1
  194. package/agent-docs/author/search.sections/use-the-search-box.md +1 -1
  195. package/agent-docs/author/search.sections/write-a-custom-provider.md +1 -1
  196. package/agent-docs/author/snippets.md +5 -1
  197. package/agent-docs/author/taxonomy.md +1 -1
  198. package/agent-docs/author/templates.md +16 -8
  199. package/agent-docs/author/templates.sections/built-in-feature-templates.md +3 -3
  200. package/agent-docs/author/templates.sections/built-in-templates.md +3 -3
  201. package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +3 -3
  202. package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +12 -4
  203. package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +3 -3
  204. package/agent-docs/author/templates.sections/project-added-templates.md +3 -3
  205. package/agent-docs/author/templates.sections/related-reading.md +3 -3
  206. package/agent-docs/author/templates.sections/scaffold-a-page.md +7 -7
  207. package/agent-docs/author/templates.sections/short-cli-and-derived-values.md +3 -3
  208. package/agent-docs/author/templates.sections/what-every-template-gives-you.md +3 -3
  209. package/agent-docs/author/workspace/commands.md +2 -2
  210. package/agent-docs/author/workspace.md +8 -2
  211. package/agent-docs/author/writing-style.md +27 -5
  212. package/agent-docs/author/writing-style.sections/adapt-this-example.md +3 -3
  213. package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +6 -4
  214. package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +3 -3
  215. package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +3 -3
  216. package/agent-docs/author/writing-style.sections/feature-availability.md +36 -0
  217. package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +3 -3
  218. package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +12 -4
  219. package/agent-docs/author/writing-style.sections/procedures-and-examples.md +3 -3
  220. package/agent-docs/author/writing-style.sections/related-reading.md +3 -3
  221. package/agent-docs/author/writing-style.sections/review-a-draft.md +3 -3
  222. package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +3 -3
  223. package/agent-docs/author/writing-style.sections/voice-and-explanations.md +3 -3
  224. package/agent-docs/changelog/2026-10-14-agent-readiness.md +2 -2
  225. package/agent-docs/changelog/2026-10-15-evaluation-builds.md +2 -2
  226. package/agent-docs/changelog/2026-10-16-navigation-layouts.md +2 -2
  227. package/agent-docs/changelog/2026-10-17-mcp-hosting.md +2 -2
  228. package/agent-docs/changelog/2026-10-18-search-and-tooltips.md +2 -2
  229. package/agent-docs/changelog/2026-10-19-visual-navigation.md +2 -2
  230. package/agent-docs/changelog/2026-10-25.md +2 -2
  231. package/agent-docs/changelog/2026-10-26.md +2 -2
  232. package/agent-docs/changelog/2026-10-27.md +2 -2
  233. package/agent-docs/changelog/2026-10-28.md +89 -0
  234. package/agent-docs/changelog/authoring-preview.md +2 -2
  235. package/agent-docs/changelog/authoring-search.md +3 -3
  236. package/agent-docs/changelog/authoring-tools.md +2 -2
  237. package/agent-docs/changelog/working-tree-skill.md +2 -2
  238. package/agent-docs/changelog.md +11 -3
  239. package/agent-docs/chat/checks.md +1 -1
  240. package/agent-docs/chat/checks.sections/answer-ahead-of-time.md +1 -1
  241. package/agent-docs/chat/checks.sections/answer-for-one-audience.md +1 -1
  242. package/agent-docs/chat/checks.sections/answer-without-a-model.md +1 -1
  243. package/agent-docs/chat/checks.sections/follow-up-questions.md +1 -1
  244. package/agent-docs/chat/checks.sections/how-an-answer-is-checked.md +1 -1
  245. package/agent-docs/chat/checks.sections/questions-with-several-parts.md +1 -1
  246. package/agent-docs/chat/checks.sections/related-reading.md +1 -1
  247. package/agent-docs/chat/checks.sections/reuse-answers.md +1 -1
  248. package/agent-docs/chat/host.md +1 -1
  249. package/agent-docs/chat/host.sections/cap-the-daily-spend.md +1 -1
  250. package/agent-docs/chat/host.sections/keep-a-record-of-questions.md +1 -1
  251. package/agent-docs/chat/host.sections/related-reading.md +1 -1
  252. package/agent-docs/chat/passage-index.md +2 -2
  253. package/agent-docs/chat/passage-index.sections/build-the-index.md +2 -2
  254. package/agent-docs/chat/passage-index.sections/embed-passages.md +2 -2
  255. package/agent-docs/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md +2 -2
  256. package/agent-docs/chat/passage-index.sections/limits.md +2 -2
  257. package/agent-docs/chat/passage-index.sections/passage-ids-and-links.md +2 -2
  258. package/agent-docs/chat/passage-index.sections/related-reading.md +2 -2
  259. package/agent-docs/chat/passage-index.sections/what-a-passage-contains.md +2 -2
  260. package/agent-docs/chat/prepared-answers.md +1 -1
  261. package/agent-docs/chat/settings.md +2 -2
  262. package/agent-docs/chat/settings.sections/choose-the-scorer.md +2 -2
  263. package/agent-docs/chat/settings.sections/configure-chat.md +2 -2
  264. package/agent-docs/chat/settings.sections/configure-retrieval.md +2 -2
  265. package/agent-docs/chat/settings.sections/related-reading.md +2 -2
  266. package/agent-docs/chat/settings.sections/send-extra-request-fields.md +2 -2
  267. package/agent-docs/chat/settings.sections/use-more-than-one-model.md +2 -2
  268. package/agent-docs/chat/settings.sections/when-the-scorer-is-down.md +2 -2
  269. package/agent-docs/chat/setup.md +1 -1
  270. package/agent-docs/chat.md +1 -1
  271. package/agent-docs/cli.md +2 -2
  272. package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +2 -2
  273. package/agent-docs/cli.sections/author-pages.md +2 -2
  274. package/agent-docs/cli.sections/build-and-serve.md +2 -2
  275. package/agent-docs/cli.sections/inspect-config-and-operations.md +2 -2
  276. package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +2 -2
  277. package/agent-docs/cli.sections/related-reading.md +2 -2
  278. package/agent-docs/cli.sections/search-and-chat.md +2 -2
  279. package/agent-docs/cli.sections/start-a-project.md +2 -2
  280. package/agent-docs/cli.sections/working-tree-authoring-tools.md +2 -2
  281. package/agent-docs/config/apis.md +2 -2
  282. package/agent-docs/config/content.md +2 -2
  283. package/agent-docs/config/content.sections/authoring.md +2 -2
  284. package/agent-docs/config/content.sections/badges.md +2 -2
  285. package/agent-docs/config/content.sections/callouts.md +2 -2
  286. package/agent-docs/config/content.sections/cookbooks.md +2 -2
  287. package/agent-docs/config/content.sections/frontmatter.md +2 -2
  288. package/agent-docs/config/content.sections/readerfilters.md +2 -2
  289. package/agent-docs/config/content.sections/related-reading.md +2 -2
  290. package/agent-docs/config/content.sections/relationships.md +2 -2
  291. package/agent-docs/config/content.sections/snippets.md +2 -2
  292. package/agent-docs/config/content.sections/templates.md +2 -2
  293. package/agent-docs/config/content.sections/variables.md +2 -2
  294. package/agent-docs/config/examples.md +22 -14
  295. package/agent-docs/config/examples.sections/feature-showcase.md +21 -13
  296. package/agent-docs/config/examples.sections/minimal-site.md +15 -10
  297. package/agent-docs/config/examples.sections/multilingual-help-center.md +15 -10
  298. package/agent-docs/config/examples.sections/parcel-api-documentation.md +15 -10
  299. package/agent-docs/config/examples.sections/related-reading.md +15 -10
  300. package/agent-docs/config/examples.sections/shared-company-preset.md +16 -11
  301. package/agent-docs/config/integrations.md +2 -2
  302. package/agent-docs/config/outputs.md +17 -13
  303. package/agent-docs/config/outputs.sections/exports.md +16 -13
  304. package/agent-docs/config/outputs.sections/metadata.md +3 -3
  305. package/agent-docs/config/outputs.sections/related-reading.md +3 -3
  306. package/agent-docs/config/publishing.md +2 -2
  307. package/agent-docs/config/publishing.sections/navigation.md +2 -2
  308. package/agent-docs/config/publishing.sections/redirects.md +2 -2
  309. package/agent-docs/config/publishing.sections/related-reading.md +2 -2
  310. package/agent-docs/config/site.md +2 -2
  311. package/agent-docs/config/site.sections/related-reading.md +2 -2
  312. package/agent-docs/config/site.sections/theme.md +2 -2
  313. package/agent-docs/config.md +2 -2
  314. package/agent-docs/configuration.md +22 -20
  315. package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +2 -2
  316. package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +5 -5
  317. package/agent-docs/configuration.sections/extract-a-section-with-include.md +4 -4
  318. package/agent-docs/configuration.sections/inspect-and-validate-changes.md +6 -6
  319. package/agent-docs/configuration.sections/related-reading.md +2 -2
  320. package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +2 -2
  321. package/agent-docs/configuration.sections/share-defaults-through-extends.md +7 -7
  322. package/agent-docs/configuration.sections/start-with-one-working-file.md +8 -6
  323. package/agent-docs/configuration.sections/understand-the-three-stages.md +2 -2
  324. package/agent-docs/configuration.sections/understand-where-paths-point.md +2 -2
  325. package/agent-docs/connect/mcp.md +1 -1
  326. package/agent-docs/content-delivery/agents.md +86 -0
  327. package/agent-docs/content-delivery/api.md +130 -0
  328. package/agent-docs/content-delivery/client.md +79 -0
  329. package/agent-docs/content-delivery/http-api/operations/get-content-representation-fa1d2e3f.md +394 -0
  330. package/agent-docs/content-delivery/http-api/operations/get-content-representation-head-4052375c.md +256 -0
  331. package/agent-docs/content-delivery/http-api/operations/get-content-resource-849f1c49.md +911 -0
  332. package/agent-docs/content-delivery/http-api/operations/get-content-resource-head-0a352acd.md +246 -0
  333. package/agent-docs/content-delivery/http-api/operations/list-content-resources-8e977ec7.md +913 -0
  334. package/agent-docs/content-delivery/http-api/operations/list-content-resources-head-b67cbad9.md +236 -0
  335. package/agent-docs/content-delivery/http-api.md +78 -0
  336. package/agent-docs/content-delivery/manifest.md +79 -0
  337. package/agent-docs/content-delivery/publish.md +72 -0
  338. package/agent-docs/content-delivery/render.md +73 -0
  339. package/agent-docs/content-delivery/rest.md +108 -0
  340. package/agent-docs/content-delivery/sections.md +110 -0
  341. package/agent-docs/content-delivery/select.md +100 -0
  342. package/agent-docs/content-delivery.md +79 -0
  343. package/agent-docs/contribute/agent-skills.md +1 -1
  344. package/agent-docs/cookbooks/authoring.md +7 -3
  345. package/agent-docs/cookbooks/site-workflows.md +8 -4
  346. package/agent-docs/cookbooks/welcome-email.md +7 -3
  347. package/agent-docs/documents.json +7707 -6283
  348. package/agent-docs/example-api/cedar/create-enrollment-7af3e5d2.md +2 -2
  349. package/agent-docs/example-api/cedar/get-legacy-parcel-6758d051.md +2 -2
  350. package/agent-docs/example-api/cedar/get-parcel-edee10e6.md +2 -2
  351. package/agent-docs/example-api/cedar/list-parcels-0345fb5f.md +2 -2
  352. package/agent-docs/example-api/cedar/parcel-delivered-7d1ba6db.md +2 -2
  353. package/agent-docs/example-api/cedar/upload-manifest-1af17891.md +2 -2
  354. package/agent-docs/example-api/cedar.md +2 -2
  355. package/agent-docs/example-api/create-note.md +2 -2
  356. package/agent-docs/example-api/generated/get-note-cbedb319.md +2 -2
  357. package/agent-docs/example-api/write-note.md +2 -2
  358. package/agent-docs/explore.md +2 -2
  359. package/agent-docs/glossary.md +3 -7
  360. package/agent-docs/ingredients/audit-site.md +2 -2
  361. package/agent-docs/ingredients/build-site.md +2 -2
  362. package/agent-docs/ingredients/compile-framework.md +2 -2
  363. package/agent-docs/ingredients/complete-page.md +2 -2
  364. package/agent-docs/ingredients/inspect-agent-bundle.md +2 -2
  365. package/agent-docs/ingredients/inspect-build.md +2 -2
  366. package/agent-docs/ingredients/preview-site.md +2 -2
  367. package/agent-docs/ingredients/refresh-agent-bundle.md +2 -2
  368. package/agent-docs/ingredients/scaffold-page.md +2 -2
  369. package/agent-docs/non-goals.md +2 -2
  370. package/agent-docs/provenance.json +4 -4
  371. package/agent-docs/publish/agent-discovery.md +1 -1
  372. package/agent-docs/publish/agent-friendliness.md +1 -1
  373. package/agent-docs/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md +1 -1
  374. package/agent-docs/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md +1 -1
  375. package/agent-docs/publish/agent-friendliness.sections/evidence-has-a-scope.md +1 -1
  376. package/agent-docs/publish/agent-friendliness.sections/keep-shared-instructions-complete.md +1 -1
  377. package/agent-docs/publish/agent-friendliness.sections/related-reading.md +1 -1
  378. package/agent-docs/publish/agent-friendliness.sections/secret-handshake.md +1 -1
  379. package/agent-docs/publish/agent-friendliness.sections/try-the-page-controls.md +1 -1
  380. package/agent-docs/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md +1 -1
  381. package/agent-docs/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md +1 -1
  382. package/agent-docs/publish/agent-friendliness.sections/what-an-agent-reads.md +1 -1
  383. package/agent-docs/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md +1 -1
  384. package/agent-docs/publish/api-references.md +10 -8
  385. package/agent-docs/publish/api-references.sections/author-the-reference-page.md +1 -1
  386. package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +1 -1
  387. package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +1 -1
  388. package/agent-docs/publish/api-references.sections/{generate-many-pages-selectively.md → next-steps.md} +28 -2
  389. package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +1 -1
  390. package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +1 -1
  391. package/agent-docs/publish/api-references.sections/register-the-operation.md +1 -1
  392. package/agent-docs/publish/api-references.sections/related-reading.md +1 -1
  393. package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +1 -1
  394. package/agent-docs/publish/api-references.sections/what-readers-get.md +1 -1
  395. package/agent-docs/publish/audit.md +1 -1
  396. package/agent-docs/publish/audit.sections/add-project-tests.md +1 -1
  397. package/agent-docs/publish/audit.sections/check-agent-evaluation-reports.md +1 -1
  398. package/agent-docs/publish/audit.sections/check-before-pushing.md +1 -1
  399. package/agent-docs/publish/audit.sections/connect-a-documentation-test-suite.md +1 -1
  400. package/agent-docs/publish/audit.sections/read-the-report.md +1 -1
  401. package/agent-docs/publish/audit.sections/related-reading.md +1 -1
  402. package/agent-docs/publish/content-export.md +33 -17
  403. package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +4 -4
  404. package/agent-docs/publish/content-export.sections/check-the-result.md +3 -3
  405. package/agent-docs/publish/content-export.sections/export-selected-pages.md +13 -10
  406. package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +6 -4
  407. package/agent-docs/publish/content-export.sections/prerequisites.md +4 -4
  408. package/agent-docs/publish/content-export.sections/related-reading.md +3 -3
  409. package/agent-docs/publish/content-export.sections/review-exported-api-material.md +4 -4
  410. package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +4 -4
  411. package/agent-docs/publish/content-export.sections/upgrade-an-existing-integration.md +34 -0
  412. package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +5 -5
  413. package/agent-docs/publish/content-negotiation.md +2 -2
  414. package/agent-docs/publish/content-negotiation.sections/hosting-contract.md +2 -2
  415. package/agent-docs/publish/content-negotiation.sections/missing-pages.md +2 -2
  416. package/agent-docs/publish/content-negotiation.sections/related-reading.md +2 -2
  417. package/agent-docs/publish/content-negotiation.sections/validators-and-manifest-links.md +2 -2
  418. package/agent-docs/publish/content-negotiation.sections/verify-the-deployed-url.md +2 -2
  419. package/agent-docs/publish/content-negotiation.sections/what-if-the-host-cannot-negotiate.md +2 -2
  420. package/agent-docs/publish/content-negotiation.sections/what-shoalrun-builds-and-what-the-host-does.md +2 -2
  421. package/agent-docs/publish/content-negotiation.sections/why-this-matters.md +2 -2
  422. package/agent-docs/publish/deployment-check.md +2 -2
  423. package/agent-docs/publish/evals.md +1 -1
  424. package/agent-docs/publish/evals.sections/add-the-audit-hook.md +1 -1
  425. package/agent-docs/publish/evals.sections/check-the-report.md +1 -1
  426. package/agent-docs/publish/evals.sections/define-a-task-file.md +1 -1
  427. package/agent-docs/publish/evals.sections/diagnose-a-different-build.md +1 -1
  428. package/agent-docs/publish/evals.sections/prepare-a-report-for-the-built-site.md +1 -1
  429. package/agent-docs/publish/evals.sections/related-reading.md +1 -1
  430. package/agent-docs/publish/evals.sections/run-and-review-the-tasks.md +1 -1
  431. package/agent-docs/publish/evals.sections/shoalrun-s-own-example.md +1 -1
  432. package/agent-docs/publish/host-adapters.md +1 -1
  433. package/agent-docs/publish/manni.md +1 -1
  434. package/agent-docs/publish/manni.sections/check-the-result.md +1 -1
  435. package/agent-docs/publish/manni.sections/how-this-site-uses-manni.md +1 -1
  436. package/agent-docs/publish/manni.sections/optional-custom-policies.md +1 -1
  437. package/agent-docs/publish/manni.sections/prerequisites.md +1 -1
  438. package/agent-docs/publish/mcp-analytics.md +1 -1
  439. package/agent-docs/publish/mcp-analytics.sections/adapter-exports.md +1 -1
  440. package/agent-docs/publish/mcp-analytics.sections/enable-analytics.md +1 -1
  441. package/agent-docs/publish/mcp-analytics.sections/event-fields-and-service-mappings.md +1 -1
  442. package/agent-docs/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md +1 -1
  443. package/agent-docs/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md +1 -1
  444. package/agent-docs/publish/mcp-analytics.sections/related-reading.md +1 -1
  445. package/agent-docs/publish/mcp-analytics.sections/safeguards-and-limits.md +1 -1
  446. package/agent-docs/publish/mcp.md +12 -10
  447. package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +2 -2
  448. package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +7 -7
  449. package/agent-docs/publish/mcp.sections/configure-the-client.md +5 -5
  450. package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +2 -2
  451. package/agent-docs/publish/mcp.sections/related-reading.md +4 -2
  452. package/agent-docs/publish/mcp.sections/search-then-read.md +2 -2
  453. package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +2 -2
  454. package/agent-docs/publish/mcp.sections/verify-the-connection.md +2 -2
  455. package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +2 -2
  456. package/agent-docs/publish/openapi-extension-mappings.md +2 -2
  457. package/agent-docs/publish/output.md +14 -14
  458. package/agent-docs/publish/output.sections/api-contracts.md +3 -3
  459. package/agent-docs/publish/output.sections/code-highlighting.md +3 -3
  460. package/agent-docs/publish/output.sections/current-limits.md +4 -4
  461. package/agent-docs/publish/output.sections/incremental-sync.md +3 -3
  462. package/agent-docs/publish/output.sections/manifest-records-and-sections.md +3 -3
  463. package/agent-docs/publish/output.sections/navigation-section-indexes.md +3 -3
  464. package/agent-docs/publish/output.sections/page-formats.md +3 -3
  465. package/agent-docs/publish/output.sections/published-output-contract.md +3 -3
  466. package/agent-docs/publish/output.sections/reader-appearance-and-controls.md +3 -3
  467. package/agent-docs/publish/output.sections/related-reading.md +3 -3
  468. package/agent-docs/publish/output.sections/response-identity.md +3 -3
  469. package/agent-docs/publish/output.sections/site-files.md +3 -3
  470. package/agent-docs/publish/output.sections/validate-an-existing-build-locally.md +5 -5
  471. package/agent-docs/publish/output.sections/where-files-go.md +11 -11
  472. package/agent-docs/publish/publications.md +1 -1
  473. package/agent-docs/publish/revisions.md +1 -1
  474. package/agent-docs/publish/seo.md +17 -3
  475. package/agent-docs/publish/seo.sections/related-reading.md +28 -0
  476. package/agent-docs/publish/seo.sections/set-the-public-address.md +36 -0
  477. package/agent-docs/publish/seo.sections/what-agents-receive.md +28 -0
  478. package/agent-docs/publish/seo.sections/what-the-build-adds.md +42 -0
  479. package/agent-docs/publish/seo.sections/write-the-page-title-and-summary.md +43 -0
  480. package/agent-docs/publish/single-source-sites.md +1 -1
  481. package/agent-docs/publish/troubleshooting.md +1 -1
  482. package/agent-docs/publish/vercel.md +1 -1
  483. package/agent-docs/publish/vercel.sections/check-the-deployment.md +1 -1
  484. package/agent-docs/publish/vercel.sections/include-an-mcp-endpoint.md +1 -1
  485. package/agent-docs/publish/vercel.sections/prepare-your-project.md +1 -1
  486. package/agent-docs/publish/vercel.sections/related-reading.md +1 -1
  487. package/agent-docs/publish.md +1 -1
  488. package/agent-docs/recipes/add-page.md +3 -3
  489. package/agent-docs/recipes/add-page.sections/audit-the-shoalrun-docs-project.md +2 -2
  490. package/agent-docs/recipes/add-page.sections/before-you-start.md +2 -3
  491. package/agent-docs/recipes/add-page.sections/build-the-shoalrun-docs-site.md +2 -2
  492. package/agent-docs/recipes/add-page.sections/check-agent-search-and-page-lookup.md +2 -2
  493. package/agent-docs/recipes/add-page.sections/check-the-built-page-artifacts.md +2 -2
  494. package/agent-docs/recipes/add-page.sections/check-the-outcome.md +2 -2
  495. package/agent-docs/recipes/add-page.sections/complete-the-guide-and-add-navigation.md +2 -2
  496. package/agent-docs/recipes/add-page.sections/install-the-site-dependencies.md +2 -2
  497. package/agent-docs/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md +3 -2
  498. package/agent-docs/recipes/add-page.sections/related-reading.md +2 -2
  499. package/agent-docs/recipes/add-page.sections/scaffold-a-new-guide.md +2 -2
  500. package/agent-docs/recipes/audit-docs.md +2 -3
  501. package/agent-docs/recipes/build-docs.md +2 -3
  502. package/agent-docs/recipes/preview-hybrid-search.md +2 -2
  503. package/agent-docs/recipes/preview-page.md +2 -3
  504. package/agent-docs/recipes/queue-email.md +2 -2
  505. package/agent-docs/recipes/refresh-agent-docs.md +21 -3
  506. package/agent-docs/recipes/send-welcome-email.md +2 -2
  507. package/agent-docs/reference/agent-skills.md +2 -2
  508. package/agent-docs/search-and-chat.md +1 -1
  509. package/agent-docs/search-index.json +1 -1
  510. package/agent-docs/start.md +7 -3
  511. package/agent-docs/start.sections/build-this-site.md +1 -1
  512. package/agent-docs/start.sections/migrating-from-github-packages.md +35 -0
  513. package/agent-docs/start.sections/prerequisites.md +1 -1
  514. package/agent-docs/start.sections/start-your-own-project.md +1 -1
  515. package/agent-docs/status.md +2 -2
  516. package/agent-docs/styling/color-modes.md +6 -2
  517. package/agent-docs/styling/footer.md +10 -8
  518. package/agent-docs/styling/header.md +5 -3
  519. package/agent-docs/styling/layouts.md +27 -5
  520. package/agent-docs/styling/layouts.sections/build-a-landing-page.md +7 -4
  521. package/agent-docs/styling/layouts.sections/build-a-splash-page.md +7 -4
  522. package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +7 -4
  523. package/agent-docs/styling/layouts.sections/customize-the-hero.md +7 -4
  524. package/agent-docs/styling/layouts.sections/hero.md +8 -5
  525. package/agent-docs/styling/layouts.sections/hide-the-table-of-contents-or-give-content-more-room.md +54 -0
  526. package/agent-docs/styling/layouts.sections/html-markdown-and-agents.md +43 -0
  527. package/agent-docs/styling/layouts.sections/related-reading.md +7 -4
  528. package/agent-docs/styling/palettes.md +6 -2
  529. package/agent-docs/styling/share-images.md +6 -2
  530. package/agent-docs/styling/themes.md +6 -3
  531. package/agent-docs/styling/try.md +3 -15
  532. package/dist/api.js +70 -3
  533. package/dist/authoring-hints.d.ts +3 -0
  534. package/dist/authoring-hints.js +35 -0
  535. package/dist/authoring-project.d.ts +1 -1
  536. package/dist/authoring-project.js +2 -0
  537. package/dist/authoring-validation.js +2 -0
  538. package/dist/code-samples.js +22 -11
  539. package/dist/compiler-config.d.ts +1 -0
  540. package/dist/compiler-config.js +13 -0
  541. package/dist/compiler.js +2 -1
  542. package/dist/component-names.js +1 -1
  543. package/dist/component-transform.js +7 -1
  544. package/dist/content-delivery-contract.d.ts +108 -0
  545. package/dist/content-delivery-contract.js +15 -0
  546. package/dist/content-delivery-transport.d.ts +3 -0
  547. package/dist/content-delivery-transport.js +47 -0
  548. package/dist/content-delivery-validation.d.ts +7 -0
  549. package/dist/content-delivery-validation.js +122 -0
  550. package/dist/content-delivery.d.ts +21 -0
  551. package/dist/content-delivery.js +119 -0
  552. package/dist/content-export-anchors.d.ts +11 -0
  553. package/dist/content-export-anchors.js +79 -0
  554. package/dist/content-export-command.d.ts +4 -2
  555. package/dist/content-export-command.js +15 -2
  556. package/dist/content-export-comparison.d.ts +16 -0
  557. package/dist/content-export-comparison.js +48 -0
  558. package/dist/content-export-config.d.ts +17 -0
  559. package/dist/content-export-config.js +47 -3
  560. package/dist/content-export-render.js +20 -1
  561. package/dist/content-export.d.ts +5 -1
  562. package/dist/content-export.js +193 -40
  563. package/dist/content-mount.d.ts +11 -0
  564. package/dist/content-mount.js +73 -0
  565. package/dist/content-rest-client.d.ts +12 -0
  566. package/dist/content-rest-client.js +162 -0
  567. package/dist/content-rest-contract.d.ts +27 -0
  568. package/dist/content-rest-contract.js +9 -0
  569. package/dist/content-rest-server.d.ts +7 -0
  570. package/dist/content-rest-server.js +99 -0
  571. package/dist/content-source.d.ts +3 -1
  572. package/dist/frontmatter.js +8 -7
  573. package/dist/html-renderer.js +25 -0
  574. package/dist/markdown-sections.d.ts +2 -1
  575. package/dist/markdown-sections.js +8 -18
  576. package/dist/page-renderer.js +5 -3
  577. package/dist/publication-plan.js +2 -1
  578. package/dist/scaffold-placeholders.d.ts +2 -0
  579. package/dist/scaffold-placeholders.js +19 -0
  580. package/dist/section-identity.d.ts +24 -0
  581. package/dist/section-identity.js +137 -0
  582. package/examples/content-delivery/README.md +87 -0
  583. package/examples/content-delivery/app.js +91 -0
  584. package/examples/content-delivery/content/billing.mdx +22 -0
  585. package/examples/content-delivery/docs.config.yaml +36 -0
  586. package/examples/content-delivery/index.html +25 -0
  587. package/examples/content-delivery/preview.mjs +86 -0
  588. package/examples/content-delivery/snippets/refund-window.mdx +3 -0
  589. package/examples/help-drawer/README.md +2 -2
  590. package/examples/help-drawer/app.js +3 -3
  591. package/package.json +6 -3
  592. package/schemas/content-export.schema.json +469 -33
  593. package/schemas/content-rest.openapi.json +1627 -0
  594. package/skills/shoalrun-author/SKILL.md +2 -0
  595. package/styles/site.css +4 -1
  596. package/agent-docs/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt +0 -33
  597. package/agent-docs/publish/api-references.sections/add-useful-examples.md +0 -36
  598. package/agent-docs/publish/api-references.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +0 -36
  599. package/agent-docs/publish/api-references.sections/link-guides-to-api-references.md +0 -36
  600. package/agent-docs/publish/api-references.sections/map-extension-values-to-shoalrun-status.md +0 -36
  601. package/agent-docs/publish/api-references.sections/publish-several-versions.md +0 -36
  602. package/agent-docs/publish/api-references.sections/use-a-template-for-editorial-context.md +0 -36
@@ -7,6 +7,8 @@ export type ContentExportOptions = {
7
7
  publication?: Variant;
8
8
  publicBase?: string;
9
9
  review?: boolean;
10
+ previousManifest?: string;
11
+ failOnRemoved?: boolean;
10
12
  };
11
13
  /** Export selected source content; never invoke the website shell/compiler. */
12
14
  export declare function exportContent(configFile: string, destination: string, options?: ContentExportOptions): Promise<{
@@ -14,8 +16,10 @@ export declare function exportContent(configFile: string, destination: string, o
14
16
  output: string;
15
17
  publication: Variant;
16
18
  formats: ExportFormat[];
19
+ resources: number;
17
20
  documents: number;
18
21
  documentIds: string[];
22
+ comparison: import("./content-export-comparison.js").ContentExportComparison;
19
23
  assets: number;
20
24
  digest: string;
21
25
  apiReview: {
@@ -24,7 +28,7 @@ export declare function exportContent(configFile: string, destination: string, o
24
28
  }[];
25
29
  diagnostics: {
26
30
  code: string;
27
- documentId: string;
31
+ documentId?: string;
28
32
  message: string;
29
33
  }[];
30
34
  }>;
@@ -22,13 +22,21 @@ import { ExportAssets, exportDigest } from './content-export-assets.js';
22
22
  import { portableTree, passiveHtml, portableMarkdown } from './content-export-render.js';
23
23
  import { checkOutputDirectory } from './output-location.js';
24
24
  import { commitArtifacts } from './output-commit.js';
25
- import { heading, root } from './content.js';
26
- import { outputUrl } from './representation-tree.js';
25
+ import { heading, root, parse, transformMdx } from './content.js';
26
+ import { outputUrl, publicTree } from './representation-tree.js';
27
27
  import { resolveSubjectDeprecation, subjectDeprecationNotice } from './subject-deprecation.js';
28
28
  import { resolveAuthoredChange, authoredChangeNotice } from './authored-change.js';
29
+ import { resolveSnippetValues } from './snippets.js';
30
+ import { isolateExportTree, markExportSource, exportHeadingInventory, preserveExportHeadingIds } from './content-export-anchors.js';
31
+ import { selectSection } from './section-identity.js';
32
+ import { compareContentManifests } from './content-export-comparison.js';
29
33
  const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
30
34
  const keyFor = (doc) => `${doc.frontmatter.id}|${doc.variant.channel}|${doc.variant.version}|${doc.variant.language}`;
31
- const resourceKey = (doc) => `${doc.frontmatter.id.replace(/[^A-Za-z0-9_-]/g, '-').slice(0, 60) || 'document'}-${exportDigest(keyFor(doc)).slice(0, 16)}`;
35
+ const resourceIdentity = (item) => JSON.stringify([item.ref.kind, item.ref.kind === 'snippet' ? item.ref.id : item.ref.documentId, item.ref.kind === 'section' ? item.ref.sectionId : null, item.doc.variant.channel, item.doc.variant.version, item.doc.variant.language]);
36
+ // Pages and their sections share a source; named snippet instances do not.
37
+ const sourceKeyFor = (doc, kind = 'document') => JSON.stringify([kind, doc.frontmatter.id, doc.variant.channel, doc.variant.version, doc.variant.language]);
38
+ const selectedSourceKey = (item) => sourceKeyFor(item.doc, item.ref.kind === 'snippet' ? 'snippet' : 'document');
39
+ const resourceKey = (item) => `resource-${exportDigest(resourceIdentity(item)).slice(0, 24)}`;
32
40
  const sameVariant = (a, b) => ['channel', 'version', 'language'].every(key => a[key] === b[key]);
33
41
  const visitTree = (node, visit) => {
34
42
  if (!node || typeof node !== 'object')
@@ -85,7 +93,7 @@ export async function exportContent(configFile, destination, options = {}) {
85
93
  const metadataDependencies = new Set();
86
94
  const workspace = await prepareContentWorkspace({ base, basePath, config, loaded, variants: [publication], language, readerFilters, metadataProvider, metadataDependencies, allowRouteCollisions: true });
87
95
  const { docs: eligible, apiPlan, snippets, sourceForOperation } = workspace;
88
- const ids = new Set(target.documents);
96
+ const ids = new Set(target.resources ? target.resources.filter(item => item.kind !== 'snippet').map(item => item.documentId) : target.documents);
89
97
  for (const id of ids) {
90
98
  const doc = [...eligible.values()].find(doc => doc.frontmatter.id === id);
91
99
  if (!doc)
@@ -93,8 +101,8 @@ export async function exportContent(configFile, destination, options = {}) {
93
101
  if (!matchesContentFilter(doc.readerFilters, target.contentFilter))
94
102
  throw new Error(`Requested export document ${id} is excluded by the export contentFilter`);
95
103
  }
96
- const docs = new Map([...eligible].filter(([, doc]) => (!target.documents || ids.has(doc.frontmatter.id)) && matchesContentFilter(doc.readerFilters, target.contentFilter)).sort(([, a], [, b]) => compare(keyFor(a), keyFor(b))));
97
- if (!docs.size)
104
+ const docs = new Map([...eligible].filter(([, doc]) => (!(target.documents || target.resources) || ids.has(doc.frontmatter.id)) && matchesContentFilter(doc.readerFilters, target.contentFilter)).sort(([, a], [, b]) => compare(keyFor(a), keyFor(b))));
105
+ if (!docs.size && !target.resources?.some(item => item.kind === 'snippet'))
98
106
  throw new Error('Export selection matched no eligible pages');
99
107
  const plugins = await loadComponentPlugins(loaded, { browser: false });
100
108
  const materialized = await materializePages({ variables: isConfigMapping(config.variables) ? config.variables : {}, frontmatterConfig: config.frontmatter, publications, docs, linkDocuments: eligible, apiPlan, sourceForOperation,
@@ -106,6 +114,7 @@ export async function exportContent(configFile, destination, options = {}) {
106
114
  const cookbooks = validateCookbooks(config.cookbooks, configFile);
107
115
  const local = new Map([...eligible.values()].map(doc => [doc.frontmatter.id, doc]));
108
116
  const diagnostics = [];
117
+ const requiredNotices = new Map();
109
118
  for (const page of materialized.rendered) {
110
119
  const use = { targets: [], queries: [] };
111
120
  page.doc.tree = resolveCardTree(page.doc.tree, page.doc, eligible, publicationRelationships(edges, local), new Set(apiPlan.knownOperations.keys()), use, config);
@@ -114,18 +123,78 @@ export async function exportContent(configFile, destination, options = {}) {
114
123
  const change = resolveAuthoredChange(page.doc, eligible);
115
124
  const existing = page.doc.tree;
116
125
  // Preserve authored notices in both output representations.
117
- page.doc.tree = root([
126
+ const notices = [
118
127
  { type: 'docRepresentation', representation: 'html', children: [...subjectDeprecationNotice(deprecation, 'html').children, ...authoredChangeNotice(change, 'html').children] },
119
- { type: 'docRepresentation', representation: 'markdown', children: [...subjectDeprecationNotice(deprecation, 'markdown').children, ...authoredChangeNotice(change, 'markdown').children] },
120
- ...existing.children
121
- ]);
128
+ { type: 'docRepresentation', representation: 'markdown', children: [...subjectDeprecationNotice(deprecation, 'markdown').children, ...authoredChangeNotice(change, 'markdown').children] }
129
+ ];
130
+ requiredNotices.set(keyFor(page.doc), notices);
131
+ page.doc.tree = root([...notices, ...existing.children]);
122
132
  const found = new Set();
123
133
  visitTree(page.doc.tree, node => { if (['docTabs', 'docWalkthrough', 'docReaderSection', 'docCollapsible', 'docTooltip', 'docInfoHint', 'docCookbookChooser'].includes(node.type))
124
134
  found.add(node.type); });
125
135
  if (found.size)
126
136
  diagnostics.push({ code: 'static-content', documentId: page.doc.frontmatter.id, message: 'Interactions and reader sections are exported as complete labeled content.' });
127
137
  }
128
- const diagrams = await resolveDiagramTrees(materialized.rendered.map(page => page.doc.tree));
138
+ // Materialized snippets can share nodes with their registry definition.
139
+ // Isolate each document before assigning source provenance.
140
+ for (const doc of docs.values()) {
141
+ doc.tree = isolateExportTree(doc.tree);
142
+ markExportSource(doc.tree);
143
+ }
144
+ const selected = [];
145
+ const selections = target.resources ?? [...docs.values()].map(doc => ({ kind: 'page', documentId: doc.frontmatter.id }));
146
+ for (const selection of selections) {
147
+ if (selection.kind === 'snippet') {
148
+ const definition = snippets.get(selection.snippetId);
149
+ if (!definition)
150
+ throw new Error(`Unknown export snippet ${selection.snippetId}`);
151
+ // This is an explicit isolated context. It has no containing page, operations,
152
+ // relationships, page variables, or inherited publication/access metadata.
153
+ const snippetDocument = { file: definition.file, body: '', tree: root([]), variant: publication,
154
+ route: `/__content_snippets/${encodeURIComponent(selection.id)}`, markdownRoute: '',
155
+ frontmatter: { id: selection.id, title: selection.title, summary: selection.summary, type: 'snippet', slug: '/', access: { policy: 'public' } } };
156
+ const checkSnippet = (id, seen = new Set()) => {
157
+ if (seen.has(id))
158
+ return;
159
+ seen.add(id);
160
+ const source = snippets.get(id);
161
+ if (!source)
162
+ throw new Error(`Unknown snippet ${id}`);
163
+ visitTree(source.tree, node => {
164
+ if (['RelatedReading', 'DocCard', 'DocCards', 'DocCollection', 'CookbookChooser', 'ApiExample', 'ApiSchema', 'FrontmatterReference', 'Anchor'].includes(node.name))
165
+ throw new Error(`Snippet instance ${selection.id}: <${node.name}> needs page context`);
166
+ if (node.name === 'Snippet') {
167
+ const child = node.attributes?.find((a) => a.name === 'id')?.value;
168
+ if (typeof child === 'string')
169
+ checkSnippet(child, seen);
170
+ }
171
+ });
172
+ };
173
+ checkSnippet(selection.snippetId);
174
+ const invocation = parse.parse(`<Snippet id=${JSON.stringify(selection.snippetId)} values={${JSON.stringify(selection.values ?? {})}} />`);
175
+ snippetDocument.tree = transformMdx(invocation, snippetDocument, new Map([...eligible.values()].map(doc => [doc.frontmatter.id, doc])), snippets, isConfigMapping(config.variables) ? config.variables : {}, [], resolveCalloutTypes(config.callouts, configFile), base, readerFilters, {}, publications, resolveBadgeVariants(config.badges, configFile), plugins.registry);
176
+ visitTree(snippetDocument.tree, node => { if (/^doc(?:Card|Collection|Related|Cookbook|Api)/.test(node.type))
177
+ throw new Error(`Snippet instance ${selection.id} needs page context`); });
178
+ snippetDocument.tree = isolateExportTree(snippetDocument.tree);
179
+ markExportSource(snippetDocument.tree);
180
+ selected.push({ ref: { kind: 'snippet', id: selection.id }, doc: snippetDocument, tree: snippetDocument.tree,
181
+ title: selection.title, summary: selection.summary, type: 'snippet', source: { snippetId: selection.snippetId, valuesDigest: exportDigest(JSON.stringify(resolveSnippetValues(selection.snippetId, definition, config.variables, undefined, selection.values ?? {}))) } });
182
+ }
183
+ else {
184
+ const doc = [...docs.values()].find(doc => doc.frontmatter.id === selection.documentId);
185
+ if (selection.kind === 'page')
186
+ selected.push({ ref: { kind: 'page', documentId: doc.frontmatter.id }, doc,
187
+ tree: root([heading(1, doc.frontmatter.title), ...doc.tree.children]), title: doc.frontmatter.title, summary: doc.frontmatter.summary, type: doc.frontmatter.type });
188
+ else {
189
+ const slice = selectSection(doc.tree, selection.sectionId, doc.frontmatter.standaloneSections ?? [], doc.frontmatter.id);
190
+ selected.push({ ref: { kind: 'section', documentId: doc.frontmatter.id, sectionId: selection.sectionId }, doc,
191
+ tree: root([...(requiredNotices.get(keyFor(doc)) ?? []), ...slice.tree.children]), meaningTree: slice.tree, title: slice.section.title,
192
+ summary: doc.frontmatter.summary, type: 'section', source: { documentId: doc.frontmatter.id } });
193
+ }
194
+ }
195
+ }
196
+ selected.sort((a, b) => compare(resourceIdentity(a), resourceIdentity(b)));
197
+ const diagrams = await resolveDiagramTrees(selected.map(item => item.tree));
129
198
  const assets = new ExportAssets(target.publicBase);
130
199
  const assetRootsOrigin = options.target && target.assetRoots.length ? explainSegments(loaded, ['exports', options.target, 'assetRoots']).source.file : configFile;
131
200
  const roots = [workspace.contentDir, ...target.assetRoots.map(root => path.resolve(path.dirname(assetRootsOrigin), root))];
@@ -134,13 +203,15 @@ export async function exportContent(configFile, destination, options = {}) {
134
203
  assets.register(asset.route, { content: asset.svg });
135
204
  for (const [url, contract] of materialized.focusedContracts)
136
205
  assets.register(url, { content: contract.content });
137
- for (const doc of docs.values())
138
- visitTree(doc.tree, node => {
206
+ for (const item of selected) {
207
+ const doc = item.doc;
208
+ visitTree(item.tree, node => {
139
209
  if (typeof node.file === 'string' && typeof node.url === 'string' && ['docImage', 'image', 'definition'].includes(node.type))
140
- assets.register(node.url, { file: node.file }, keyFor(doc));
210
+ assets.register(node.url, { file: node.file }, selectedSourceKey(item));
141
211
  if (node.type === 'docHero' && node.image?.file)
142
- assets.register(node.image.url, { file: node.image.file }, keyFor(doc));
212
+ assets.register(node.image.url, { file: node.image.file }, selectedSourceKey(item));
143
213
  });
214
+ }
144
215
  const reviews = await reviewApiPublication(configFile, apiPlan, materialized.rendered, materialized.apiEmbedUses, materialized.focusedContracts, [...materialized.apiPublications.values()].map(source => ({ apiId: source.apiId, sourceUrl: source.sourceUrl })), sourceForOperation, 'report');
145
216
  const unreviewed = reviews.filter(review => (target.apiReview[review.apiId] ?? configField(apiPlan.apiDefinitions[review.apiId].publicReview, 'digest')) !== review.digest);
146
217
  if (unreviewed.length && !options.review)
@@ -158,24 +229,62 @@ export async function exportContent(configFile, destination, options = {}) {
158
229
  const trees = new Map();
159
230
  const anchors = new Map();
160
231
  const routes = new Set([...eligible.values()].map(doc => doc.route));
161
- for (const doc of docs.values())
232
+ const sourceInventories = new Map();
233
+ const sourceAliases = new Map();
234
+ for (const item of selected)
162
235
  for (const format of target.formats) {
163
- const tree = portableTree(root([heading(1, doc.frontmatter.title), ...doc.tree.children]), format, routes, basePath);
164
- trees.set(`${keyFor(doc)}:${format}`, tree);
165
- // Markdown anchors are renderer-dependent. HTML is generated and scoped here.
166
- if (format === 'html')
167
- anchors.set(keyFor(doc), passiveHtml(tree, `sr-${resourceKey(doc)}`, false).anchors);
236
+ const sourceKey = `${selectedSourceKey(item)}:${format}`;
237
+ if (!sourceInventories.has(sourceKey))
238
+ sourceInventories.set(sourceKey, exportHeadingInventory(portableTree(structuredClone(item.doc.tree), format, routes, basePath)));
239
+ const tree = portableTree(structuredClone(item.tree), format, routes, basePath);
240
+ if (item.ref.kind !== 'page') {
241
+ const meaning = item.meaningTree ? portableTree(structuredClone(item.meaningTree), format, routes, basePath) : tree;
242
+ const body = (meaning.children ?? []).filter((node) => node.type !== 'heading' && node.type !== 'definition' && node.type !== 'footnoteDefinition');
243
+ if (!portableMarkdown(root(body)).trim())
244
+ throw new Error(`Resource ${resourceIdentity(item)} has no content in ${format}`);
245
+ }
246
+ const aliases = preserveExportHeadingIds(tree, sourceInventories.get(sourceKey), format);
247
+ sourceAliases.set(`${resourceIdentity(item)}:${format}`, aliases);
248
+ trees.set(`${resourceIdentity(item)}:${format}`, tree);
249
+ // Resolve anchors independently in each representation, before URL rewriting.
250
+ anchors.set(`${resourceIdentity(item)}:${format}`, passiveHtml(tree, `sr-${resourceKey(item)}`, false).anchors);
168
251
  }
252
+ const canonicalAnchors = new Map();
253
+ const verifiedCanonicalAnchors = (destination, format) => {
254
+ const key = `${sourceKeyFor(destination)}:${format}`;
255
+ if (canonicalAnchors.has(key))
256
+ return canonicalAnchors.get(key);
257
+ const source = sourceInventories.get(key);
258
+ if (!source || destination.endpoint)
259
+ throw new Error(`Cannot validate canonical fragments in ${destination.frontmatter.id}; select the target resource explicitly`);
260
+ const reserved = ['main', 'docs-navigation', 'docs-sections', 'documentation-menu', 'page-outline', 'nav-filter', 'examples-title', 'api-view-select'];
261
+ const explicit = new Set();
262
+ visitTree(destination.tree, node => {
263
+ if (node.type === 'docSection' && node.sectionId)
264
+ reserved.push(node.sectionId);
265
+ const alias = node.data?.hProperties?.['data-shoalrun-section-id'];
266
+ if (typeof alias === 'string')
267
+ explicit.add(alias);
268
+ });
269
+ const native = exportHeadingInventory(publicTree(structuredClone(destination.tree), 'html', routes, 'light', basePath), reserved);
270
+ const verified = new Set([...explicit].filter(id => native.ids.has(id)));
271
+ for (const [headingKey, id] of source.headings)
272
+ if (native.headings.get(headingKey) === id)
273
+ verified.add(id);
274
+ canonicalAnchors.set(key, verified);
275
+ return verified;
276
+ };
169
277
  const records = [];
170
278
  const artifacts = new Map();
171
- for (const doc of docs.values()) {
279
+ for (const item of selected) {
280
+ const doc = item.doc;
172
281
  const externalDependencies = new Map();
173
282
  const usedAssets = new Set();
174
283
  const representations = {};
175
- const canonicalUrl = origin && canonicalDestination(doc) ? `${origin}${doc.route}` : undefined;
284
+ const canonicalUrl = item.ref.kind !== 'snippet' && origin && canonicalDestination(doc) ? `${origin}${doc.route}` : undefined;
176
285
  for (const format of target.formats) {
177
286
  const links = [];
178
- const tree = trees.get(`${keyFor(doc)}:${format}`);
287
+ const tree = trees.get(`${resourceIdentity(item)}:${format}`);
179
288
  const resolve = async (node) => {
180
289
  // Native adapters can express ordinary links/images as semantic elements.
181
290
  const properties = node.data?.hProperties;
@@ -207,24 +316,56 @@ export async function exportContent(configFile, destination, options = {}) {
207
316
  if (destination) {
208
317
  let href;
209
318
  let kind;
210
- if (docs.has(keyFor(destination))) {
211
- const fragment = decodeURIComponent(parsed.hash.slice(1));
212
- const targetAnchors = anchors.get(keyFor(destination));
213
- const anchor = fragment && format === 'html' ? targetAnchors?.find(item => item.id === fragment || item.exportedId === fragment) : undefined;
214
- if (fragment && format === 'html' && !anchor)
215
- throw new Error(`Missing export anchor ${fragment} in ${destination.frontmatter.id}`);
216
- const suffix = parsed.search + (fragment ? `#${format === 'html' ? anchor.exportedId : parsed.hash.slice(1)}` : '');
217
- href = destination === doc && !parsed.search && fragment ? suffix : `${target.publicBase}content/${resourceKey(destination)}.${format === 'html' ? 'html' : 'md'}${suffix}`;
218
- kind = 'document';
319
+ const fragment = decodeURIComponent(parsed.hash.slice(1));
320
+ const candidates = selected.filter(candidate => candidate.ref.kind !== 'snippet' && keyFor(candidate.doc) === keyFor(destination));
321
+ const hasAnchor = (candidate) => sourceAliases.get(`${resourceIdentity(candidate)}:${format}`)?.has(fragment);
322
+ let chosen = destination === doc && fragment && hasAnchor(item) ? item : undefined;
323
+ if (!chosen && fragment) {
324
+ const matching = candidates.filter(candidate => candidate.ref.kind === 'section' && hasAnchor(candidate));
325
+ if (matching.length > 1)
326
+ throw new Error(`Ambiguous fragment ${fragment} in ${destination.frontmatter.id}`);
327
+ chosen = matching[0];
328
+ }
329
+ chosen ??= candidates.find(candidate => candidate.ref.kind === 'page');
330
+ // Clean Markdown has no explicit alias anchors. Prefer an actual
331
+ // section resource for those references, otherwise the canonical HTML.
332
+ if (chosen && format === 'markdown' && fragment && chosen.ref.kind === 'page') {
333
+ const targetId = sourceAliases.get(`${resourceIdentity(chosen)}:${format}`)?.get(fragment);
334
+ const target = anchors.get(`${resourceIdentity(chosen)}:${format}`)?.find(entry => entry.id === targetId);
335
+ if (target && !target.title)
336
+ chosen = candidates.find(candidate => candidate.ref.kind === 'section' && candidate.ref.sectionId === fragment);
337
+ }
338
+ if (chosen) {
339
+ const targetAnchors = anchors.get(`${resourceIdentity(chosen)}:${format}`);
340
+ const targetId = sourceAliases.get(`${resourceIdentity(chosen)}:${format}`)?.get(fragment);
341
+ const anchor = fragment ? targetAnchors.find(entry => entry.id === targetId) : undefined;
342
+ if (fragment && !anchor)
343
+ throw new Error(`Missing export anchor ${fragment} in ${destination.frontmatter.id} (${format})`);
344
+ // A section-resource URL is sufficient when addressing its leading
345
+ // section; clean Markdown does not publish explicit HTML anchors.
346
+ const leadingSection = chosen.ref.kind === 'section' && chosen.ref.sectionId === fragment;
347
+ const markdownAnchor = anchor?.id ?? fragment;
348
+ const suffix = parsed.search + (fragment && !(format === 'markdown' && leadingSection) ? `#${format === 'html' ? anchor.exportedId : markdownAnchor}` : '');
349
+ href = chosen === item && !parsed.search && fragment && format === 'html' ? suffix : `${target.publicBase}content/${resourceKey(chosen)}.${format === 'html' ? 'html' : 'md'}${suffix}`;
350
+ kind = 'resource';
219
351
  }
220
352
  else {
221
353
  if (!origin || !canonicalDestination(destination))
222
354
  throw new Error(`Document ${destination.frontmatter.id} is outside the export and has no eligible canonical website fallback`);
355
+ if (fragment) {
356
+ const inventory = sourceInventories.get(`${sourceKeyFor(destination)}:${format}`);
357
+ if (!inventory)
358
+ throw new Error(`Cannot validate canonical anchor ${fragment} in unselected document ${destination.frontmatter.id}; select that page or section explicitly`);
359
+ if (!inventory.ids.has(fragment))
360
+ throw new Error(`Missing source anchor ${fragment} in ${destination.frontmatter.id} (${format})`);
361
+ if (!verifiedCanonicalAnchors(destination, format).has(fragment))
362
+ throw new Error(`Cannot verify canonical anchor ${fragment} in ${destination.frontmatter.id}; select its target resource explicitly`);
363
+ }
223
364
  href = `${origin}${destination.route}${parsed.search}${parsed.hash}`;
224
365
  kind = 'canonical';
225
366
  }
226
367
  const key = `link-${links.length + 1}`;
227
- links.push({ key, kind, href, documentId: destination.frontmatter.id, ...(parsed.hash ? { fragment: decodeURIComponent(parsed.hash.slice(1)) } : {}), ...(parsed.search ? { query: parsed.search.slice(1) } : {}) });
368
+ links.push({ key, kind, href, ...(chosen ? { ref: chosen.ref } : {}), ...(fragment ? { fragment } : {}), ...(parsed.search ? { query: parsed.search.slice(1) } : {}) });
228
369
  node.url = href;
229
370
  if (format === 'html' && node.type === 'link')
230
371
  node.data = { ...node.data, hProperties: { ...node.data?.hProperties, 'data-export-link': key } };
@@ -237,7 +378,7 @@ export async function exportContent(configFile, destination, options = {}) {
237
378
  links.push({ key: `link-${links.length + 1}`, kind: 'external', href: node.url });
238
379
  }
239
380
  else {
240
- const asset = await assets.resolve(value, doc.file, keyFor(doc));
381
+ const asset = await assets.resolve(value, doc.file, selectedSourceKey(item));
241
382
  if (!asset)
242
383
  throw new Error(`Unresolved local export ${node.type === 'image' ? 'image' : 'link'} ${value} in ${doc.frontmatter.id}`);
243
384
  usedAssets.add(asset.path);
@@ -250,15 +391,15 @@ export async function exportContent(configFile, destination, options = {}) {
250
391
  await resolve(child);
251
392
  };
252
393
  await resolve(tree);
253
- const filename = `content/${resourceKey(doc)}.${format === 'html' ? 'html' : 'md'}`;
254
- const rendered = format === 'html' ? passiveHtml(tree, `sr-${resourceKey(doc)}`) : undefined;
394
+ const filename = `content/${resourceKey(item)}.${format === 'html' ? 'html' : 'md'}`;
395
+ const rendered = format === 'html' ? passiveHtml(tree, `sr-${resourceKey(item)}`) : undefined;
255
396
  const content = rendered?.html ?? portableMarkdown(tree);
256
397
  artifacts.set(filename, content);
257
398
  representations[format] = { path: filename, mediaType: format === 'html' ? 'text/html' : 'text/markdown', bytes: Buffer.byteLength(content), digest: exportDigest(content), anchors: rendered?.anchors ?? [], links };
258
399
  }
259
400
  if (externalDependencies.size)
260
401
  diagnostics.push({ code: 'external-render-dependencies', documentId: doc.frontmatter.id, message: `${externalDependencies.size} remote image(s) remain external; this document is not offline-complete.` });
261
- records.push({ id: doc.frontmatter.id, publication, title: doc.frontmatter.title, summary: doc.frontmatter.summary, type: doc.frontmatter.type, ...(canonicalUrl ? { canonicalUrl } : {}), representations, assets: [...usedAssets].sort(), externalDependencies: [...externalDependencies.values()].sort((a, b) => compare(a.url, b.url)) });
402
+ records.push({ ref: item.ref, publication, title: item.title, summary: item.summary, type: item.type, ...(item.source ? { source: item.source } : {}), ...(canonicalUrl ? { canonicalUrl } : {}), representations, assets: [...usedAssets].sort(), externalDependencies: [...externalDependencies.values()].sort((a, b) => compare(a.url, b.url)) });
262
403
  }
263
404
  for (const [filename, bytes] of assets.artifacts)
264
405
  artifacts.set(filename, bytes);
@@ -291,8 +432,15 @@ export async function exportContent(configFile, destination, options = {}) {
291
432
  artifacts.set('NOTICES.txt', notices);
292
433
  const manifest = { schemaVersion: 1, kind: 'shoalrun-content-export', publicBase: target.publicBase, publication,
293
434
  review: { status: unreviewed.length ? 'required' : 'ok', apis: reviews.map(row => ({ apiId: row.apiId, digest: row.digest })) },
294
- documents: records, assets: [...assets.records.values()].sort((a, b) => compare(a.path, b.path)),
435
+ resources: records, assets: [...assets.records.values()].sort((a, b) => compare(a.path, b.path)),
295
436
  files: [...artifacts].map(([filename, content]) => ({ path: filename, bytes: Buffer.byteLength(content), digest: exportDigest(content) })).sort((a, b) => compare(a.path, b.path)), diagnostics };
437
+ const previous = options.previousManifest ? JSON.parse(await readFile(options.previousManifest, 'utf8')) : undefined;
438
+ const comparison = compareContentManifests(previous, manifest);
439
+ if (options.failOnRemoved && !options.previousManifest)
440
+ throw new Error('failOnRemoved requires previousManifest');
441
+ if (options.failOnRemoved && comparison.removed.length)
442
+ throw new Error(`Export removes ${comparison.removed.length} previously exported resource(s)`);
443
+ diagnostics.push(...comparison.diagnostics);
296
444
  const bundleDigest = exportDigest(JSON.stringify(manifest));
297
445
  artifacts.set('manifest.json', JSON.stringify({ ...manifest, digest: bundleDigest }, null, 2) + '\n');
298
446
  const inputs = [...noticeFiles, ...loaded.dependencies, ...metadataDependencies, ...plugins.dependencies, ...apiPlan.api.dependencies, ...[...eligible.values()].map(doc => doc.file), ...[...snippets.values()].map(snippet => snippet.file)];
@@ -300,8 +448,13 @@ export async function exportContent(configFile, destination, options = {}) {
300
448
  // No export can replace a directory containing an allowed asset root.
301
449
  for (const directory of roots)
302
450
  checkOutputDirectory(destination, base, directory, inputs);
451
+ if (unreviewed.length) {
452
+ const prior = await readFile(path.join(destination, 'manifest.json'), 'utf8').then(JSON.parse).catch(() => undefined);
453
+ if (prior?.review?.status === 'ok')
454
+ throw new Error('Review candidate cannot overwrite an approved export; choose a separate review destination');
455
+ }
303
456
  await commitArtifacts(path.resolve(destination), artifacts, undefined, 'export');
304
457
  return { status: unreviewed.length ? 'needs-review' : 'ok', output: path.resolve(destination), publication, formats: target.formats,
305
- documents: records.length, documentIds: records.map(doc => doc.id), assets: assets.records.size, digest: bundleDigest,
458
+ resources: records.length, documents: records.filter(item => item.ref.kind === 'page').length, documentIds: records.flatMap(item => item.ref.kind === 'page' ? [item.ref.documentId] : []), comparison, assets: assets.records.size, digest: bundleDigest,
306
459
  apiReview: reviews.map(row => ({ apiId: row.apiId, digest: row.digest })), diagnostics };
307
460
  }
@@ -0,0 +1,11 @@
1
+ import type { ContentAnchor, ContentLink, ContentResult } from './content-delivery-contract.js';
2
+ export type ContentMount = {
3
+ anchors: readonly ContentAnchor[];
4
+ links: readonly ContentLink[];
5
+ unmount(): void;
6
+ };
7
+ /** Mount trusted compiler output, not arbitrary HTML. This is not a sanitizer. */
8
+ export declare function mountContent(container: Element, result: ContentResult, options?: {
9
+ instanceId?: string;
10
+ signal?: AbortSignal;
11
+ }): ContentMount;
@@ -0,0 +1,73 @@
1
+ import { ContentDeliveryError, contentRefKey } from './content-delivery-contract.js';
2
+ /** Mount trusted compiler output, not arbitrary HTML. This is not a sanitizer. */
3
+ export function mountContent(container, result, options = {}) {
4
+ options.signal?.throwIfAborted();
5
+ if (result.format !== 'html')
6
+ throw new ContentDeliveryError('unsupported_format', 'Mounting requires HTML content.');
7
+ const instance = options.instanceId ?? `content-${globalThis.crypto.randomUUID()}`;
8
+ if (!/^[A-Za-z][A-Za-z0-9_-]{0,127}$/.test(instance))
9
+ throw new ContentDeliveryError('invalid_content', 'Invalid mount instance ID.');
10
+ const document = container.ownerDocument;
11
+ const template = document.createElement('template');
12
+ template.innerHTML = result.content;
13
+ const ids = new Map();
14
+ for (const element of template.content.querySelectorAll('[id]')) {
15
+ const old = element.id;
16
+ const next = `${instance}-${old}`;
17
+ if (!old || ids.has(old))
18
+ throw new ContentDeliveryError('invalid_content', 'Duplicate or empty content ID.');
19
+ const existing = document.getElementById(next);
20
+ if (existing && (existing === container || !container.contains(existing)))
21
+ throw new ContentDeliveryError('invalid_content', 'Mount instance ID is already in use.');
22
+ ids.set(old, next);
23
+ element.id = next;
24
+ }
25
+ const tokenAttributes = ['aria-labelledby', 'aria-describedby', 'aria-controls', 'aria-owns', 'aria-flowto', 'headers'];
26
+ const singleAttributes = ['aria-activedescendant', 'aria-details', 'aria-errormessage', 'for', 'list', 'form'];
27
+ const rewrite = (id) => ids.get(id) ?? id;
28
+ const links = result.representation.links.map(link => ({ ...link }));
29
+ for (const element of template.content.querySelectorAll('*')) {
30
+ for (const attribute of tokenAttributes)
31
+ if (element.hasAttribute(attribute))
32
+ element.setAttribute(attribute, element.getAttribute(attribute).split(/\s+/).map(rewrite).join(' '));
33
+ for (const attribute of singleAttributes)
34
+ if (element.hasAttribute(attribute))
35
+ element.setAttribute(attribute, rewrite(element.getAttribute(attribute)));
36
+ const href = element.getAttribute('href');
37
+ if (href?.startsWith('#')) {
38
+ let id;
39
+ try {
40
+ id = decodeURIComponent(href.slice(1));
41
+ }
42
+ catch {
43
+ throw new ContentDeliveryError('invalid_content', 'Malformed content fragment.');
44
+ }
45
+ if (ids.has(id))
46
+ element.setAttribute('href', '#' + ids.get(id));
47
+ }
48
+ const key = element.getAttribute('data-export-link');
49
+ const link = key ? links.find(link => link.key === key) : undefined;
50
+ if (link?.kind === 'resource' && link.ref && contentRefKey(link.ref) === contentRefKey(result.resource.ref) && link.fragment && !link.query) {
51
+ const anchor = result.representation.anchors.find(anchor => anchor.id === link.fragment || anchor.exportedId === link.fragment);
52
+ const id = anchor && ids.get(anchor.exportedId);
53
+ if (id) {
54
+ element.setAttribute('href', '#' + id);
55
+ link.href = '#' + id;
56
+ }
57
+ }
58
+ }
59
+ const anchors = result.representation.anchors.map(anchor => {
60
+ const exportedId = ids.get(anchor.exportedId);
61
+ if (!exportedId)
62
+ throw new ContentDeliveryError('invalid_content', 'Declared anchor is absent from HTML.');
63
+ return Object.freeze({ ...anchor, exportedId });
64
+ });
65
+ options.signal?.throwIfAborted();
66
+ const mounted = [...template.content.childNodes];
67
+ container.replaceChildren(template.content);
68
+ return Object.freeze({ anchors: Object.freeze(anchors), links: Object.freeze(links.map(link => Object.freeze(link))),
69
+ unmount() { for (const node of mounted)
70
+ if (node.parentNode === container)
71
+ node.remove(); },
72
+ });
73
+ }
@@ -0,0 +1,12 @@
1
+ import type { ContentSnapshot, ContentPublication } from './content-delivery-contract.js';
2
+ import type { ContentDeliveryLimits } from './content-delivery.js';
3
+ export type RestContentSourceOptions = {
4
+ baseUrl: string | URL;
5
+ publication: ContentPublication;
6
+ revision?: string;
7
+ fetch?: typeof globalThis.fetch;
8
+ signal?: AbortSignal;
9
+ limits?: ContentDeliveryLimits;
10
+ };
11
+ /** Preloads a REST inventory and pins all subsequent reads to that revision. */
12
+ export declare function openRestContentSource(options: RestContentSourceOptions): Promise<ContentSnapshot>;