@shoalrun/cli 0.1.0-alpha.12 → 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 (193) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +45 -5
  3. package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +3 -1
  4. package/agent-docs/SNAPSHOT.json +5 -5
  5. package/agent-docs/api-docs/support.md +11 -10
  6. package/agent-docs/author/components.md +13 -1
  7. package/agent-docs/author/frontmatter-reference.md +28 -25
  8. package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +3 -1
  9. package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +3 -1
  10. package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +3 -1
  11. package/agent-docs/author/frontmatter-reference.sections/html-markdown-and-agents.md +3 -1
  12. package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +3 -1
  13. package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +3 -1
  14. package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +3 -1
  15. package/agent-docs/author/frontmatter-reference.sections/related-reading.md +3 -1
  16. package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +3 -1
  17. package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +3 -1
  18. package/agent-docs/author/frontmatter.md +5 -2
  19. package/agent-docs/author/frontmatter.sections/audience-badges.md +1 -1
  20. package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +1 -1
  21. package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +1 -1
  22. package/agent-docs/author/frontmatter.sections/optional-native-fields.md +5 -2
  23. package/agent-docs/author/frontmatter.sections/publication-fields.md +1 -1
  24. package/agent-docs/author/frontmatter.sections/publishing-policy.md +1 -1
  25. package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +1 -1
  26. package/agent-docs/author/frontmatter.sections/related-reading.md +1 -1
  27. package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +1 -1
  28. package/agent-docs/author/frontmatter.sections/seo-fields.md +1 -1
  29. package/agent-docs/author/frontmatter.sections/validation-rules.md +1 -1
  30. package/agent-docs/author/markdown-metadata.md +13 -5
  31. package/agent-docs/author/navigation.md +12 -1
  32. package/agent-docs/author/navigation.sections/arrange-authored-pages.md +1 -1
  33. package/agent-docs/author/navigation.sections/fill-an-api-tag-group.md +1 -1
  34. package/agent-docs/author/navigation.sections/hide-group-page-counts.md +12 -1
  35. package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +1 -1
  36. package/agent-docs/author/navigation.sections/local-api-preview.md +1 -1
  37. package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +1 -1
  38. package/agent-docs/author/navigation.sections/optionally-split-a-large-menu-into-files.md +1 -1
  39. package/agent-docs/author/navigation.sections/reach-navigation-while-reading.md +1 -1
  40. package/agent-docs/author/navigation.sections/related-reading.md +1 -1
  41. package/agent-docs/author/navigation.sections/split-navigation-into-tabs.md +1 -1
  42. package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +1 -1
  43. package/agent-docs/author/templates.md +10 -2
  44. package/agent-docs/author/templates.sections/built-in-feature-templates.md +1 -1
  45. package/agent-docs/author/templates.sections/built-in-templates.md +1 -1
  46. package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +1 -1
  47. package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +10 -2
  48. package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +1 -1
  49. package/agent-docs/author/templates.sections/project-added-templates.md +1 -1
  50. package/agent-docs/author/templates.sections/related-reading.md +1 -1
  51. package/agent-docs/author/templates.sections/scaffold-a-page.md +1 -1
  52. package/agent-docs/author/templates.sections/short-cli-and-derived-values.md +1 -1
  53. package/agent-docs/author/templates.sections/what-every-template-gives-you.md +1 -1
  54. package/agent-docs/author/workspace.md +7 -1
  55. package/agent-docs/author/writing-style.md +13 -1
  56. package/agent-docs/author/writing-style.sections/adapt-this-example.md +1 -1
  57. package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +1 -1
  58. package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +1 -1
  59. package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +1 -1
  60. package/agent-docs/author/writing-style.sections/feature-availability.md +36 -0
  61. package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +1 -1
  62. package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +1 -1
  63. package/agent-docs/author/writing-style.sections/procedures-and-examples.md +1 -1
  64. package/agent-docs/author/writing-style.sections/related-reading.md +1 -1
  65. package/agent-docs/author/writing-style.sections/review-a-draft.md +1 -1
  66. package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +1 -1
  67. package/agent-docs/author/writing-style.sections/voice-and-explanations.md +1 -1
  68. package/agent-docs/changelog/2026-10-28.md +89 -0
  69. package/agent-docs/changelog.md +9 -1
  70. package/agent-docs/config/outputs.md +15 -11
  71. package/agent-docs/config/outputs.sections/exports.md +14 -11
  72. package/agent-docs/config/outputs.sections/metadata.md +1 -1
  73. package/agent-docs/config/outputs.sections/related-reading.md +1 -1
  74. package/agent-docs/content-delivery/agents.md +86 -0
  75. package/agent-docs/content-delivery/api.md +130 -0
  76. package/agent-docs/content-delivery/client.md +79 -0
  77. package/agent-docs/content-delivery/http-api/operations/get-content-representation-fa1d2e3f.md +394 -0
  78. package/agent-docs/content-delivery/http-api/operations/get-content-representation-head-4052375c.md +256 -0
  79. package/agent-docs/content-delivery/http-api/operations/get-content-resource-849f1c49.md +911 -0
  80. package/agent-docs/content-delivery/http-api/operations/get-content-resource-head-0a352acd.md +246 -0
  81. package/agent-docs/content-delivery/http-api/operations/list-content-resources-8e977ec7.md +913 -0
  82. package/agent-docs/content-delivery/http-api/operations/list-content-resources-head-b67cbad9.md +236 -0
  83. package/agent-docs/content-delivery/http-api.md +78 -0
  84. package/agent-docs/content-delivery/manifest.md +79 -0
  85. package/agent-docs/content-delivery/publish.md +72 -0
  86. package/agent-docs/content-delivery/render.md +73 -0
  87. package/agent-docs/content-delivery/rest.md +108 -0
  88. package/agent-docs/content-delivery/sections.md +110 -0
  89. package/agent-docs/content-delivery/select.md +100 -0
  90. package/agent-docs/content-delivery.md +79 -0
  91. package/agent-docs/documents.json +6748 -5073
  92. package/agent-docs/provenance.json +4 -4
  93. package/agent-docs/publish/content-export.md +32 -16
  94. package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +3 -3
  95. package/agent-docs/publish/content-export.sections/check-the-result.md +2 -2
  96. package/agent-docs/publish/content-export.sections/export-selected-pages.md +12 -9
  97. package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +5 -3
  98. package/agent-docs/publish/content-export.sections/prerequisites.md +3 -3
  99. package/agent-docs/publish/content-export.sections/related-reading.md +2 -2
  100. package/agent-docs/publish/content-export.sections/review-exported-api-material.md +3 -3
  101. package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +3 -3
  102. package/agent-docs/publish/content-export.sections/upgrade-an-existing-integration.md +34 -0
  103. package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +4 -4
  104. package/agent-docs/publish/mcp.md +3 -1
  105. package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +1 -1
  106. package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +1 -1
  107. package/agent-docs/publish/mcp.sections/configure-the-client.md +1 -1
  108. package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +1 -1
  109. package/agent-docs/publish/mcp.sections/related-reading.md +3 -1
  110. package/agent-docs/publish/mcp.sections/search-then-read.md +1 -1
  111. package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +1 -1
  112. package/agent-docs/publish/mcp.sections/verify-the-connection.md +1 -1
  113. package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +1 -1
  114. package/agent-docs/publish/seo.md +16 -2
  115. package/agent-docs/publish/seo.sections/related-reading.md +28 -0
  116. package/agent-docs/publish/seo.sections/set-the-public-address.md +36 -0
  117. package/agent-docs/publish/seo.sections/what-agents-receive.md +28 -0
  118. package/agent-docs/publish/seo.sections/what-the-build-adds.md +42 -0
  119. package/agent-docs/publish/seo.sections/write-the-page-title-and-summary.md +43 -0
  120. package/agent-docs/search-index.json +1 -1
  121. package/agent-docs/styling/layouts.md +21 -3
  122. package/agent-docs/styling/layouts.sections/build-a-landing-page.md +6 -3
  123. package/agent-docs/styling/layouts.sections/build-a-splash-page.md +6 -3
  124. package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +6 -3
  125. package/agent-docs/styling/layouts.sections/customize-the-hero.md +6 -3
  126. package/agent-docs/styling/layouts.sections/hero.md +6 -3
  127. package/agent-docs/styling/layouts.sections/hide-the-table-of-contents-or-give-content-more-room.md +54 -0
  128. package/agent-docs/styling/layouts.sections/html-markdown-and-agents.md +6 -3
  129. package/agent-docs/styling/layouts.sections/related-reading.md +6 -3
  130. package/dist/api.js +70 -3
  131. package/dist/authoring-hints.d.ts +3 -0
  132. package/dist/authoring-hints.js +35 -0
  133. package/dist/authoring-project.d.ts +1 -1
  134. package/dist/authoring-project.js +2 -0
  135. package/dist/authoring-validation.js +2 -0
  136. package/dist/code-samples.js +22 -11
  137. package/dist/compiler-config.d.ts +1 -0
  138. package/dist/compiler-config.js +13 -0
  139. package/dist/compiler.js +2 -1
  140. package/dist/component-names.js +1 -1
  141. package/dist/component-transform.js +7 -1
  142. package/dist/content-delivery-contract.d.ts +108 -0
  143. package/dist/content-delivery-contract.js +15 -0
  144. package/dist/content-delivery-transport.d.ts +3 -0
  145. package/dist/content-delivery-transport.js +47 -0
  146. package/dist/content-delivery-validation.d.ts +7 -0
  147. package/dist/content-delivery-validation.js +122 -0
  148. package/dist/content-delivery.d.ts +21 -0
  149. package/dist/content-delivery.js +119 -0
  150. package/dist/content-export-anchors.d.ts +11 -0
  151. package/dist/content-export-anchors.js +79 -0
  152. package/dist/content-export-command.d.ts +4 -2
  153. package/dist/content-export-command.js +15 -2
  154. package/dist/content-export-comparison.d.ts +16 -0
  155. package/dist/content-export-comparison.js +48 -0
  156. package/dist/content-export-config.d.ts +17 -0
  157. package/dist/content-export-config.js +47 -3
  158. package/dist/content-export-render.js +20 -1
  159. package/dist/content-export.d.ts +5 -1
  160. package/dist/content-export.js +193 -40
  161. package/dist/content-mount.d.ts +11 -0
  162. package/dist/content-mount.js +73 -0
  163. package/dist/content-rest-client.d.ts +12 -0
  164. package/dist/content-rest-client.js +162 -0
  165. package/dist/content-rest-contract.d.ts +27 -0
  166. package/dist/content-rest-contract.js +9 -0
  167. package/dist/content-rest-server.d.ts +7 -0
  168. package/dist/content-rest-server.js +99 -0
  169. package/dist/content-source.d.ts +3 -1
  170. package/dist/frontmatter.js +8 -7
  171. package/dist/html-renderer.js +25 -0
  172. package/dist/markdown-sections.d.ts +2 -1
  173. package/dist/markdown-sections.js +8 -18
  174. package/dist/page-renderer.js +5 -3
  175. package/dist/publication-plan.js +2 -1
  176. package/dist/scaffold-placeholders.d.ts +2 -0
  177. package/dist/scaffold-placeholders.js +19 -0
  178. package/dist/section-identity.d.ts +24 -0
  179. package/dist/section-identity.js +137 -0
  180. package/examples/content-delivery/README.md +87 -0
  181. package/examples/content-delivery/app.js +91 -0
  182. package/examples/content-delivery/content/billing.mdx +22 -0
  183. package/examples/content-delivery/docs.config.yaml +36 -0
  184. package/examples/content-delivery/index.html +25 -0
  185. package/examples/content-delivery/preview.mjs +86 -0
  186. package/examples/content-delivery/snippets/refund-window.mdx +3 -0
  187. package/examples/help-drawer/README.md +2 -2
  188. package/examples/help-drawer/app.js +3 -3
  189. package/package.json +6 -3
  190. package/schemas/content-export.schema.json +469 -33
  191. package/schemas/content-rest.openapi.json +1627 -0
  192. package/skills/shoalrun-author/SKILL.md +2 -0
  193. package/styles/site.css +4 -1
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,9 +17,11 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
22
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
23
+
24
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
22
25
 
23
26
  | Layout | Sidebar | On this page | Use it for |
24
27
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
@@ -33,6 +36,21 @@ layout: wide
33
36
 
34
37
  An unknown value fails the build. Each preset styles all four layouts, and project CSS can target one through `html[data-layout="wide"]`, `html[data-layout="landing"]`, or `html[data-layout="splash"]`.
35
38
 
39
+ ## Hide the table of contents or give content more room
40
+
41
+ To remove the right sidebar labeled “On this page” and widen the content area, set `layout: wide`. It keeps the left navigation and gives interactive tools, large tables, and diagrams more space.
42
+
43
+ To hide the table of contents without choosing a different layout, set `tocDepth: 0`. To keep an outline with fewer heading levels, use `tocDepth: 2`. See [page metadata](https://www.shoalrun.com/author/frontmatter.md) for the supported depths.
44
+
45
+ These settings serve different goals:
46
+
47
+ | Goal | Page frontmatter |
48
+ | ------------------------------------------------------------ | ------------------------------------- |
49
+ | Give interactive content more space while keeping navigation | `layout: wide` |
50
+ | Hide “On this page” within the current layout | `tocDepth: 0` |
51
+ | Keep “On this page” but list only main sections | `tocDepth: 2` |
52
+ | Remove navigation and the outline for an entry page | `layout: landing` or `layout: splash` |
53
+
36
54
  ## Control navigation tabs
37
55
 
38
56
  The built-in layouts are `docs`, `wide`, `landing`, and `splash`. There is no `custom` layout value; use landing or splash for a custom entry page and style it with project CSS.
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,11 +17,13 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
22
  Parent page: [Full Markdown page](/styling/layouts.md)
22
23
 
23
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
27
 
25
28
  | Layout | Sidebar | On this page | Use it for |
26
29
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,11 +17,13 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
22
  Parent page: [Full Markdown page](/styling/layouts.md)
22
23
 
23
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
27
 
25
28
  | Layout | Sidebar | On this page | Use it for |
26
29
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,11 +17,13 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
22
  Parent page: [Full Markdown page](/styling/layouts.md)
22
23
 
23
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
27
 
25
28
  | Layout | Sidebar | On this page | Use it for |
26
29
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,11 +17,13 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
22
  Parent page: [Full Markdown page](/styling/layouts.md)
22
23
 
23
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
27
 
25
28
  | Layout | Sidebar | On this page | Use it for |
26
29
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,11 +17,13 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
22
  Parent page: [Full Markdown page](/styling/layouts.md)
22
23
 
23
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
27
 
25
28
  | Layout | Sidebar | On this page | Use it for |
26
29
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
@@ -0,0 +1,54 @@
1
+ ---
2
+ id: guide.layouts
3
+ title: Page layouts, landing pages, and splash pages
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
6
+ type: reference
7
+ area: appearance
8
+ subarea: appearance-layouts
9
+ canonical: /styling/layouts
10
+ ---
11
+
12
+ # Page layouts, landing pages, and splash pages
13
+
14
+ > Documentation index: [llms.min.txt](https://www.shoalrun.com/llms.min.txt) · Document manifest: [documents.json](https://www.shoalrun.com/documents.json)
15
+
16
+ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigation/docs-50f26fe22670.txt) (ID: docs). [All sections and pages](https://www.shoalrun.com/llms.min.txt)
17
+
18
+ Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
19
+
20
+ **Updated: 2026-10-28.**
21
+
22
+ Parent page: [Full Markdown page](/styling/layouts.md)
23
+
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
27
+
28
+ | Layout | Sidebar | On this page | Use it for |
29
+ | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
30
+ | `docs` | Yes | Yes | Guides and reference pages. This is the default. |
31
+ | `wide` | Yes | No | Wide tables, diagrams, and API overviews that need the full content width. |
32
+ | `landing` | No | No | Home pages and product entry points. A `Hero` replaces the page header. |
33
+ | `splash` | No | No | Marketing pages built from full-width bands. A `Hero` replaces the page header, and `Section` blocks stack edge to edge. |
34
+
35
+ ```yaml title="Frontmatter"
36
+ layout: wide
37
+ ```
38
+
39
+ An unknown value fails the build. Each preset styles all four layouts, and project CSS can target one through `html[data-layout="wide"]`, `html[data-layout="landing"]`, or `html[data-layout="splash"]`.
40
+
41
+ ## Hide the table of contents or give content more room
42
+
43
+ To remove the right sidebar labeled “On this page” and widen the content area, set `layout: wide`. It keeps the left navigation and gives interactive tools, large tables, and diagrams more space.
44
+
45
+ To hide the table of contents without choosing a different layout, set `tocDepth: 0`. To keep an outline with fewer heading levels, use `tocDepth: 2`. See [page metadata](https://www.shoalrun.com/author/frontmatter.md) for the supported depths.
46
+
47
+ These settings serve different goals:
48
+
49
+ | Goal | Page frontmatter |
50
+ | ------------------------------------------------------------ | ------------------------------------- |
51
+ | Give interactive content more space while keeping navigation | `layout: wide` |
52
+ | Hide “On this page” within the current layout | `tocDepth: 0` |
53
+ | Keep “On this page” but list only main sections | `tocDepth: 2` |
54
+ | Remove navigation and the outline for an entry page | `layout: landing` or `layout: splash` |
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,11 +17,13 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
22
  Parent page: [Full Markdown page](/styling/layouts.md)
22
23
 
23
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
27
 
25
28
  | Layout | Sidebar | On this page | Use it for |
26
29
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  id: guide.layouts
3
3
  title: Page layouts, landing pages, and splash pages
4
- summary: Configure wide, landing, and splash pages with Hero and Sections.
4
+ summary: Hide the table of contents, give interactive content more space, or
5
+ build landing and splash pages.
5
6
  type: reference
6
7
  area: appearance
7
8
  subarea: appearance-layouts
@@ -16,11 +17,13 @@ Navigation section: [Docs](https://www.shoalrun.com/.well-known/shoalrun/navigat
16
17
 
17
18
  Breadcrumbs: [Docs](https://www.shoalrun.com/what-is-shoalrun.md) > Configure and customize > Page layouts, landing pages, and splash pages
18
19
 
19
- **Updated: 2026-10-27.**
20
+ **Updated: 2026-10-28.**
20
21
 
21
22
  Parent page: [Full Markdown page](/styling/layouts.md)
22
23
 
23
- Every page uses the `docs` layout unless its frontmatter sets `layout`. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
+ Use `layout: wide` to hide “On this page” and give interactive content more space while keeping navigation. Use `tocDepth: 0` when you only want to hide the table of contents within the current layout.
25
+
26
+ Every page uses the `docs` layout unless its frontmatter sets `layout`. Choose the page structure first, then adjust individual visibility settings. Layouts change the HTML page only. The Markdown twin, search, and `llms.txt` stay the same.
24
27
 
25
28
  | Layout | Sidebar | On this page | Use it for |
26
29
  | --------- | ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
package/dist/api.js CHANGED
@@ -224,7 +224,7 @@ export class ApiReader {
224
224
  if (entries.length === 1 && /^[^?&#\s=]+$/.test(entries[0][0]) && ['string', 'number', 'boolean'].includes(typeof entries[0][1]))
225
225
  queryExpression = `${entries[0][0]}=${encodeURIComponent(String(entries[0][1]))}`;
226
226
  }
227
- if (location.startsWith('parameter:')) {
227
+ if (location.startsWith('parameter:') || location.startsWith('response-header:')) {
228
228
  const value = example.externalValue ? link(example.externalValue, 'Open external example') : inline(queryRule && location === `parameter:query:${queryRule.parameter}` ? queryExpression ?? JSON.stringify(example.value) : JSON.stringify(example.value));
229
229
  const sample = paragraph({ type: 'strong', children: [text(example.title)] }, text(': '), value, ...(example.description ? [text(` — ${example.description}`)] : []));
230
230
  sample.data = { hProperties: { className: ['api-parameter-example'] } };
@@ -465,8 +465,8 @@ export class ApiReader {
465
465
  blocks.push(heading(3, 'Responses'));
466
466
  for (const [status, initial] of Object.entries(op.responses ?? {})) {
467
467
  const { value: response, source: responseSource } = await this.deref(pathSource, initial);
468
- if (response.headers || response.links)
469
- throw new Error(`Response headers or links need an adapter: ${status}`);
468
+ if (response.links)
469
+ throw new Error(`Response links need an adapter: ${status}`);
470
470
  const description = String(response.description ?? '').trim();
471
471
  const mediaEntries = Object.entries(response.content ?? {});
472
472
  const responseBlocks = [];
@@ -474,6 +474,73 @@ export class ApiReader {
474
474
  responseBlocks.push({ type: 'docApiResponseHeader', data: { hName: 'div', hProperties: { className: ['api-response-header'] } }, children: [responseHeading, ...mediaEntries.map(([mediaType]) => ({ ...paragraph(inline(mediaType)), data: { hProperties: { className: ['api-response-media'] } } }))] });
475
475
  if (description)
476
476
  responseBlocks.push(...parsePlainMarkdown(description));
477
+ if (response.headers !== undefined && (!response.headers || typeof response.headers !== 'object' || Array.isArray(response.headers)))
478
+ throw new Error(`Response headers must be a mapping: ${status}`);
479
+ const headerNames = new Set();
480
+ const headers = [];
481
+ for (const [name, initialHeader] of Object.entries(response.headers ?? {})) {
482
+ // OpenAPI explicitly excludes Content-Type: response.content describes it.
483
+ if (name.toLowerCase() === 'content-type')
484
+ continue;
485
+ if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name))
486
+ throw new Error(`Invalid response header name: ${name}`);
487
+ if (headerNames.has(name.toLowerCase()))
488
+ throw new Error(`Duplicate response header name (case-insensitive): ${name}`);
489
+ headerNames.add(name.toLowerCase());
490
+ let header = initialHeader, headerSource = responseSource;
491
+ let overrideDescription;
492
+ const seen = new Set();
493
+ while (header?.$ref) {
494
+ if (typeof header.$ref !== 'string')
495
+ throw new Error(`Response header reference must be a string: ${name}`);
496
+ const allowed = schemaVersion === '3.1' ? ['$ref', 'description', 'summary'] : ['$ref'];
497
+ if (Object.keys(header).some(key => !allowed.includes(key)))
498
+ throw new Error(`Response header reference ${name} has unsupported siblings`);
499
+ for (const field of ['description', 'summary'])
500
+ if (header[field] !== undefined && typeof header[field] !== 'string')
501
+ throw new Error(`Invalid response header reference ${field}: ${name}`);
502
+ // Reference summary has no Header Object counterpart; OAS ignores it.
503
+ if (overrideDescription === undefined && header.description !== undefined)
504
+ overrideDescription = header.description;
505
+ const resolved = await this.ref(headerSource, header.$ref);
506
+ if (seen.has(resolved.identity))
507
+ throw new Error(`Recursive response header reference: ${name}`);
508
+ seen.add(resolved.identity);
509
+ header = resolved.value;
510
+ headerSource = resolved.source;
511
+ }
512
+ if (!header || typeof header !== 'object' || Array.isArray(header))
513
+ throw new Error(`Invalid response Header Object: ${name}`);
514
+ if (header.content !== undefined)
515
+ throw new Error(`Response header content needs an adapter: ${name}`);
516
+ const fields = new Set(['description', 'required', 'deprecated', 'schema', 'style', 'explode', 'example', 'examples']);
517
+ for (const field of Object.keys(header))
518
+ if (!fields.has(field) && !field.startsWith('x-'))
519
+ throw new Error(`Unsupported response header field ${field}: ${name}`);
520
+ for (const field of ['required', 'deprecated', 'explode'])
521
+ if (header[field] !== undefined && typeof header[field] !== 'boolean')
522
+ throw new Error(`Response header ${field} must be boolean: ${name}`);
523
+ if (header.description !== undefined && typeof header.description !== 'string')
524
+ throw new Error(`Response header description must be a string: ${name}`);
525
+ if (header.style !== undefined && header.style !== 'simple')
526
+ throw new Error(`Response header style must be simple: ${name}`);
527
+ if (header.schema === undefined)
528
+ throw new Error(`Response header requires a schema: ${name}`);
529
+ if (header.examples !== undefined && (!header.examples || typeof header.examples !== 'object' || Array.isArray(header.examples)))
530
+ throw new Error(`Response header examples must be a mapping: ${name}`);
531
+ const headerDescription = overrideDescription ?? header.description;
532
+ const detail = [heading(6, name), tagged(paragraph(text(header.required ? 'Required' : 'Optional')), 'api-parameter-presence', { 'data-required': header.required ? 'true' : 'false' })];
533
+ if (header.deprecated)
534
+ detail.push(tagged(paragraph(text('Deprecated response header.')), 'api-deprecated-note'));
535
+ if (headerDescription)
536
+ detail.push(...parsePlainMarkdown(headerDescription));
537
+ detail.push(paragraph(text(`Serialization: simple; explode: ${header.explode ?? false}.`)));
538
+ detail.push(...await this.schemaBlocks(headerSource, header.schema, schemaVersion, 6, new Set(), ['response', status, 'header', name], [], headerDescription));
539
+ await addExamples(headerSource, header, `response-header:${name}`, null, status, detail);
540
+ headers.push({ type: 'docApiParameter', data: { hName: 'section', hProperties: { className: ['api-parameter', 'api-response-header-field'] } }, children: detail });
541
+ }
542
+ if (headers.length)
543
+ responseBlocks.push(heading(5, 'Response headers'), ...headers);
477
544
  for (const [mediaType, media] of mediaEntries) {
478
545
  if (mediaEntries.length > 1)
479
546
  responseBlocks.push(tagged(heading(5, mediaType), 'api-media-heading'));
@@ -0,0 +1,3 @@
1
+ import type { ValidationFinding } from './authoring-findings.js';
2
+ /** Suggestions only: the author decides whether native relationships fit the links. */
3
+ export declare function authoringHints(body: string, file: string): ValidationFinding[];
@@ -0,0 +1,35 @@
1
+ import { parse } from './semantic-markdown.js';
2
+ const text = (node) => typeof node.value === 'string' ? node.value : (node.children ?? []).map(text).join('');
3
+ const contains = (node, predicate) => predicate(node) || (node.children ?? []).some((child) => contains(child, predicate));
4
+ /** Suggestions only: the author decides whether native relationships fit the links. */
5
+ export function authoringHints(body, file) {
6
+ let tree;
7
+ try {
8
+ tree = parse.parse(body);
9
+ }
10
+ catch {
11
+ return [];
12
+ } // Compilation reports syntax errors.
13
+ if (contains(tree, node => node.name === 'RelatedReading'))
14
+ return [];
15
+ const nodes = tree.children ?? [];
16
+ const definitions = new Map();
17
+ contains(tree, node => { if (node.type === 'definition')
18
+ definitions.set(node.identifier, node.url); return false; });
19
+ const documentLink = (node) => node.type === 'link' && node.url?.startsWith('doc:') || node.type === 'linkReference' && definitions.get(node.identifier)?.startsWith('doc:');
20
+ for (let index = 0; index < nodes.length; index++) {
21
+ const heading = nodes[index];
22
+ if (heading.type !== 'heading' || !/^related (reading|materials?)$/i.test(text(heading).trim()))
23
+ continue;
24
+ let end = index + 1;
25
+ while (end < nodes.length && !(nodes[end].type === 'heading' && nodes[end].depth <= heading.depth))
26
+ end++;
27
+ if (!nodes.slice(index + 1, end).some((node) => contains(node, documentLink)))
28
+ continue;
29
+ return [{ code: 'authoring.related-reading', severity: 'warning', file,
30
+ explanation: 'This page has a related-reading or related-material section with document links. Native relationships and RelatedReading may suit these connections.',
31
+ reference: 'guide.related-reading',
32
+ nextAction: 'Read guide.related-reading and guide.component.related-reading. Inspect the purpose and reason for each connection before choosing native relationships; keep manual links when they better fit the page.' }];
33
+ }
34
+ return [];
35
+ }
@@ -27,7 +27,7 @@ export declare const projectToolFailure: (error: unknown) => {
27
27
  schemaVersion: number;
28
28
  status: "error";
29
29
  error: {
30
- code: "invalid_input" | "internal_error" | "unknown_source" | "unsafe_path" | "invalid_project";
30
+ code: "invalid_input" | "internal_error" | "unsafe_path" | "unknown_source" | "invalid_project";
31
31
  message: string;
32
32
  };
33
33
  };
@@ -1,3 +1,4 @@
1
+ import { authoringHints } from './authoring-hints.js';
1
2
  import { createHash } from 'node:crypto';
2
3
  import { readFile, readdir, realpath } from 'node:fs/promises';
3
4
  import path from 'node:path';
@@ -121,6 +122,7 @@ export async function inspectAuthoringProject(configFile, options = {}) {
121
122
  publication: { channel: fm.channel ?? value.publications?.defaults?.channel, version: fm.version ?? value.publications?.defaults?.version, language: fm.language ?? defaultLanguage(value), ...(fm.publications ? { publications: fm.publications } : {}) },
122
123
  access: fm.access ?? null, aliases: [] });
123
124
  bodies.set(relative(file), doc.body);
125
+ findings.push(...authoringHints(doc.body, relative(file)).map(({ location, ...hint }) => hint));
124
126
  }
125
127
  catch (error) {
126
128
  findings.push({ code: 'project.invalid-page', severity: 'error', file: relative(file), explanation: error.message, nextAction: 'Repair the page metadata and inspect again.', reference: 'guide.frontmatter' });
@@ -1,3 +1,4 @@
1
+ import { authoringHints } from './authoring-hints.js';
1
2
  import { chmod, mkdir, mkdtemp, readFile, readdir, realpath, stat, writeFile } from 'node:fs/promises';
2
3
  import os from 'node:os';
3
4
  import path from 'node:path';
@@ -188,6 +189,7 @@ export async function validateAuthoringChangesWithHooks(configFile, options, hoo
188
189
  for (const file of affected) {
189
190
  try {
190
191
  const doc = await readDocument(path.join(shadow, file), loaded.value.frontmatter, undefined, capture.buffers.get(file).toString('utf8'));
192
+ report.findings.push(...authoringHints(doc.body, file));
191
193
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(doc.frontmatter.id))
192
194
  report.findings.push({ ...finding('validation.identity', 'Page IDs must begin with a letter/digit and contain only letters, digits, dots, underscores or hyphens.', 'Choose a stable ID and update its references.'), file, reference: 'guide.frontmatter-reference' });
193
195
  }
@@ -37,9 +37,10 @@ function resolve(sample) {
37
37
  headers.push(['Content-Type', sample.contentType]);
38
38
  return { headers, notes };
39
39
  }
40
+ const isHead = (sample) => sample.method.toUpperCase() === 'HEAD';
40
41
  const hasBody = (sample) => !!sample.body && !sample.body.formFields.length;
41
42
  function curl(sample) {
42
- const parts = [`curl --request ${sample.method.toUpperCase()}`, `--url ${shellQuote(sample.url)}`];
43
+ const parts = [isHead(sample) ? 'curl --head' : `curl --request ${sample.method.toUpperCase()}`, `--url ${shellQuote(sample.url)}`];
43
44
  for (const auth of sample.auth) {
44
45
  if (auth.kind === 'header')
45
46
  parts.push(`--header ${shellQuote(`${auth.name}: ${auth.value}`)}`);
@@ -76,7 +77,11 @@ function javascript(sample, node) {
76
77
  const lines = notes.map(note => `// ${note}`);
77
78
  if (node)
78
79
  lines.push('// Node.js 18 or newer provides a global fetch.');
79
- lines.push(`const response = await fetch(${JSON.stringify(sample.url)}, {`, options.join(',\n'), '});', '', 'const data = await response.json();', 'console.log(data);');
80
+ lines.push(`const response = await fetch(${JSON.stringify(sample.url)}, {`, options.join(',\n'), '});', '');
81
+ if (isHead(sample))
82
+ lines.push('console.log(response.status, Object.fromEntries(response.headers));');
83
+ else
84
+ lines.push('const body = await response.text();', "const mediaType = (response.headers.get('content-type') ?? '').split(';')[0].trim().toLowerCase();", "const data = body && (mediaType === 'application/json' || mediaType.endsWith('+json')) ? JSON.parse(body) : body;", 'console.log(data);');
80
85
  return lines.join('\n');
81
86
  }
82
87
  function python(sample) {
@@ -87,12 +92,16 @@ function python(sample) {
87
92
  if (hasBody(sample))
88
93
  lines.push(`data = ${JSON.stringify(sample.body.text)}`);
89
94
  const args = ['url', ...(headers.length ? ['headers=headers'] : []), ...(hasBody(sample) ? ['data=data'] : [])];
90
- lines.push('', `response = requests.${sample.method.toLowerCase()}(${args.join(', ')})`, 'print(response.json())');
95
+ lines.push('', `response = requests.${sample.method.toLowerCase()}(${args.join(', ')})`);
96
+ if (isHead(sample))
97
+ lines.push('print(response.status_code, dict(response.headers))');
98
+ else
99
+ lines.push('body = response.text', "media_type = response.headers.get('Content-Type', '').split(';')[0].strip().lower()", "data = response.json() if body and (media_type == 'application/json' or media_type.endswith('+json')) else body", 'print(data)');
91
100
  return lines.join('\n');
92
101
  }
93
102
  function go(sample) {
94
103
  const { headers, notes } = resolve(sample);
95
- const imports = ['"fmt"', '"io"', '"net/http"', ...(hasBody(sample) ? ['"strings"'] : [])].sort();
104
+ const imports = ['"fmt"', ...(isHead(sample) ? [] : ['"io"']), '"net/http"', ...(hasBody(sample) ? ['"strings"'] : [])].sort();
96
105
  const bodyVar = hasBody(sample) ? [`body := strings.NewReader(${goString(sample.body.text)})`, ''] : [];
97
106
  const bodyArg = hasBody(sample) ? 'body' : 'nil';
98
107
  const lines = [
@@ -103,8 +112,7 @@ function go(sample) {
103
112
  '\tif err != nil {', '\t\tpanic(err)', '\t}',
104
113
  ...headers.map(([name, value]) => `\treq.Header.Set(${JSON.stringify(name)}, ${JSON.stringify(value)})`),
105
114
  '\tres, err := http.DefaultClient.Do(req)', '\tif err != nil {', '\t\tpanic(err)', '\t}',
106
- '\tdefer res.Body.Close()', '\tdata, err := io.ReadAll(res.Body)', '\tif err != nil {', '\t\tpanic(err)', '\t}',
107
- '\tfmt.Println(string(data))', '}'
115
+ '\tdefer res.Body.Close()', ...(isHead(sample) ? ['\tfmt.Println(res.StatusCode, res.Header)'] : ['\tdata, err := io.ReadAll(res.Body)', '\tif err != nil {', '\t\tpanic(err)', '\t}', '\tfmt.Println(string(data))']), '}'
108
116
  ];
109
117
  return lines.join('\n');
110
118
  }
@@ -117,12 +125,14 @@ function java(sample) {
117
125
  'import java.net.URI;', 'import java.net.http.HttpClient;', 'import java.net.http.HttpRequest;', 'import java.net.http.HttpResponse;', '',
118
126
  'public class Main {', ' public static void main(String[] args) throws Exception {', ' HttpClient client = HttpClient.newHttpClient();',
119
127
  ' HttpRequest request = HttpRequest.newBuilder()', ` .uri(URI.create(${JSON.stringify(sample.url)}))`, ...builder, bodyMethod, ' .build();',
120
- ' HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());', ' System.out.println(response.body());', ' }', '}'
128
+ ' HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());', ...(isHead(sample) ? [' System.out.println(response.statusCode());', ' System.out.println(response.headers().map());'] : [' System.out.println(response.body());']), ' }', '}'
121
129
  ].join('\n');
122
130
  }
123
131
  function php(sample) {
124
132
  const { headers, notes } = resolve(sample);
125
133
  const array = [' CURLOPT_URL => ' + phpString(sample.url), ` CURLOPT_CUSTOMREQUEST => ${phpString(sample.method.toUpperCase())}`, ' CURLOPT_RETURNTRANSFER => true'];
134
+ if (isHead(sample))
135
+ array.push(' CURLOPT_NOBODY => true', ' CURLOPT_HEADER => true');
126
136
  if (headers.length)
127
137
  array.push(` CURLOPT_HTTPHEADER => [\n${headers.map(([name, value]) => ` ${phpString(`${name}: ${value}`)}`).join(',\n')}\n ]`);
128
138
  if (hasBody(sample))
@@ -136,15 +146,16 @@ function php(sample) {
136
146
  }
137
147
  function ruby(sample) {
138
148
  const { headers, notes } = resolve(sample);
139
- const klass = sample.method.toLowerCase() === 'get' ? 'Get' : sample.method[0].toUpperCase() + sample.method.slice(1);
149
+ const method = sample.method.toLowerCase();
150
+ const klass = method[0].toUpperCase() + method.slice(1);
140
151
  const lines = [
141
152
  ...notes.map(note => `# ${note}`),
142
153
  "require 'net/http'", "require 'uri'", '',
143
- `uri = URI(${rubyString(sample.url)})`, 'http = Net::HTTP.new(uri.host, uri.port)', 'http.use_ssl = true', '',
154
+ `uri = URI(${rubyString(sample.url)})`, 'http = Net::HTTP.new(uri.host, uri.port)', 'http.use_ssl = uri.scheme == \'https\'', '',
144
155
  `request = Net::HTTP::${klass}.new(uri)`,
145
156
  ...headers.map(([name, value]) => `request[${rubyString(name)}] = ${rubyString(value)}`),
146
157
  ...(hasBody(sample) ? [`request.body = ${rubyString(sample.body.text)}`] : []),
147
- '', 'response = http.request(request)', 'puts response.body'
158
+ '', 'response = http.request(request)', ...(isHead(sample) ? ['puts response.code', 'puts response.to_hash'] : ['puts response.body'])
148
159
  ];
149
160
  return lines.join('\n');
150
161
  }
@@ -159,7 +170,7 @@ function csharp(sample) {
159
170
  ` var request = new HttpRequestMessage(new HttpMethod(${JSON.stringify(sample.method.toUpperCase())}), ${JSON.stringify(sample.url)});`,
160
171
  ...contentHeaders.map(([name, value]) => ` request.Headers.TryAddWithoutValidation(${JSON.stringify(name)}, ${JSON.stringify(value)});`),
161
172
  ...(hasBody(sample) ? [` request.Content = new StringContent(${csharpString(sample.body.text)}, Encoding.UTF8, ${JSON.stringify(contentType)});`] : []),
162
- ' var response = await client.SendAsync(request);', ' Console.WriteLine(await response.Content.ReadAsStringAsync());', ' }', '}'
173
+ ' var response = await client.SendAsync(request);', ...(isHead(sample) ? [' Console.WriteLine((int)response.StatusCode);', ' Console.WriteLine(response.Headers);', ' Console.WriteLine(response.Content.Headers);'] : [' Console.WriteLine(await response.Content.ReadAsStringAsync());']), ' }', '}'
163
174
  ].join('\n');
164
175
  }
165
176
  // cURL comes first: the Markdown twin and agent bundle keep only that one.
@@ -58,6 +58,7 @@ export declare function configField(value: unknown, key: string): unknown;
58
58
  export declare function resolvedCompilerConfig(value: unknown): ResolvedCompilerConfig;
59
59
  /** A section-level mapping guard for validators that accept arbitrary YAML. */
60
60
  export declare function configMappingAt(value: unknown, setting: string): ConfigMapping;
61
+ export declare function navigationHeading(outputs: unknown): string | false;
61
62
  export declare function navigationCounts(outputs: unknown): boolean;
62
63
  /**
63
64
  * Apply the compiler's existing required-section checks at their original
@@ -18,6 +18,19 @@ export function configMappingAt(value, setting) {
18
18
  throw new Error(`${setting} must be a mapping`);
19
19
  return value;
20
20
  }
21
+ export function navigationHeading(outputs) {
22
+ const navigation = configField(configField(outputs, 'html'), 'navigation');
23
+ if (navigation === undefined)
24
+ return 'Explore';
25
+ const heading = configMappingAt(navigation, 'outputs.html.navigation').heading;
26
+ if (heading === undefined)
27
+ return 'Explore';
28
+ if (heading === false)
29
+ return false;
30
+ if (typeof heading !== 'string' || !heading.trim())
31
+ throw new Error('outputs.html.navigation.heading must be nonempty text or false');
32
+ return heading.trim();
33
+ }
21
34
  export function navigationCounts(outputs) {
22
35
  const navigation = configField(configField(outputs, 'html'), 'navigation');
23
36
  if (navigation === undefined)