blume 2.0.3 → 2.1.1
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.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +142 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
- package/dist/cli/chunk-313vnn40.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
- package/dist/cli/chunk-3x6x3pph.js.map +10 -0
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
- package/dist/cli/chunk-42t4jxdx.js.map +12 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
- package/dist/cli/chunk-54ztw1nj.js.map +10 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
- package/dist/cli/chunk-66w9j7p6.js +322 -0
- package/dist/cli/chunk-66w9j7p6.js.map +14 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
- package/dist/cli/chunk-7ppf1rva.js.map +10 -0
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
- package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
- package/dist/cli/chunk-cfyg47zg.js.map +10 -0
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
- package/dist/cli/chunk-e6atmn4h.js.map +36 -0
- package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
- package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
- package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
- package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
- package/dist/cli/chunk-ehweg4fr.js.map +218 -0
- package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
- package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
- package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
- package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
- package/dist/cli/chunk-gb420vvz.js.map +17 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
- package/dist/cli/chunk-hebn0tpx.js.map +14 -0
- package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
- package/dist/cli/chunk-htrwgabr.js.map +15 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
- package/dist/cli/chunk-j134vrp2.js +65 -0
- package/dist/cli/chunk-j134vrp2.js.map +10 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
- package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
- package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
- package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
- package/dist/cli/chunk-ncj7w596.js.map +35 -0
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
- package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
- package/dist/cli/chunk-nrns10mj.js.map +10 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
- package/dist/cli/chunk-t2m5j4pr.js +104 -0
- package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
- package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
- package/dist/cli/chunk-tphac74f.js +126 -0
- package/dist/cli/chunk-tphac74f.js.map +11 -0
- package/dist/cli/chunk-w1r4vase.js +18 -0
- package/dist/cli/chunk-w1r4vase.js.map +10 -0
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/index.js +31 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +26 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +9 -0
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +62 -0
- package/dist/types/components/content/api-page.d.ts +100 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +158 -0
- package/dist/types/components/openapi/security.d.ts +95 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +217 -23
- package/dist/types/core/data.d.ts +53 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +88 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +152 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +670 -56
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +18 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +26 -1
- package/dist/types/deploy/redirects.d.ts +55 -11
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +27 -10
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +16 -0
- package/dist/types/openapi/references.d.ts +30 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +119 -0
- package/dist/types/ratelimit/upstash.d.ts +46 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +89 -11
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +82 -6
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +144 -36
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +13 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/seo/metatags.d.ts +20 -0
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +54 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +71 -17
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +13 -2
- package/docs/advanced/skills.mdx +15 -1
- package/docs/cli/audit.mdx +51 -8
- package/docs/cli/doctor.mdx +5 -1
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +194 -38
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +8 -6
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +64 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +90 -0
- package/docs/configuration/search.mdx +63 -12
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +108 -2
- package/docs/content/frontmatter.mdx +80 -2
- package/docs/content/i18n.mdx +39 -4
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +32 -10
- package/docs/content/sources/contentful.mdx +35 -0
- package/docs/content/sources/custom.mdx +43 -0
- package/docs/content/sources/github-releases.mdx +39 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +31 -0
- package/docs/content/sources/remote-mdx.mdx +44 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +32 -0
- package/docs/content/syntax.mdx +69 -4
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +2 -2
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +4 -2
- package/docs/references/graphql.mdx +14 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +148 -7
- package/docs/references/scalar.mdx +3 -1
- package/package.json +43 -8
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +7 -7
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +10 -7
- package/skills/blume-migrate/references/starlight.md +11 -8
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +103 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +76 -1
- package/src/ai/cors.ts +14 -3
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +36 -6
- package/src/ai/relative-links.ts +4 -38
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +210 -66
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +42 -4
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +9 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/templates.ts +406 -108
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +38 -3
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +19 -13
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +5 -0
- package/src/audit/types.ts +4 -1
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +12 -1
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +67 -28
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/init/scaffold.ts +3 -3
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +72 -30
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +66 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +103 -0
- package/src/components/content/api-page.ts +248 -0
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +136 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +318 -47
- package/src/components/layout/Search.astro +47 -19
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +126 -0
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +32 -0
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +184 -13
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +24 -5
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +7 -4
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +65 -9
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +24 -5
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +16 -3
- package/src/components/openapi/snippets.ts +873 -10
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/client-address.ts +19 -0
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +225 -23
- package/src/core/data.ts +46 -4
- package/src/core/diagnostics.ts +8 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +84 -2
- package/src/core/includes.ts +21 -4
- package/src/core/links.ts +63 -19
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +163 -16
- package/src/core/redirect-patterns.ts +520 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +339 -66
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +228 -41
- package/src/core/sources/notion.ts +7 -1
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +19 -1
- package/src/core/ui-packs/ar.ts +44 -0
- package/src/core/ui-packs/bg.ts +46 -0
- package/src/core/ui-packs/bn.ts +44 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +45 -0
- package/src/core/ui-packs/da.ts +46 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +46 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +46 -0
- package/src/core/ui-packs/fi.ts +46 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +44 -0
- package/src/core/ui-packs/hi.ts +45 -0
- package/src/core/ui-packs/hr.ts +46 -0
- package/src/core/ui-packs/hu.ts +45 -0
- package/src/core/ui-packs/id.ts +46 -0
- package/src/core/ui-packs/it.ts +46 -0
- package/src/core/ui-packs/ja.ts +46 -0
- package/src/core/ui-packs/ko.ts +45 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +45 -0
- package/src/core/ui-packs/pl.ts +46 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +46 -0
- package/src/core/ui-packs/ro.ts +46 -0
- package/src/core/ui-packs/ru.ts +46 -0
- package/src/core/ui-packs/sk.ts +45 -0
- package/src/core/ui-packs/sr.ts +46 -0
- package/src/core/ui-packs/sv.ts +45 -0
- package/src/core/ui-packs/th.ts +44 -0
- package/src/core/ui-packs/tr.ts +46 -0
- package/src/core/ui-packs/uk.ts +46 -0
- package/src/core/ui-packs/vi.ts +46 -0
- package/src/core/ui-packs/zh-tw.ts +44 -0
- package/src/core/ui-packs/zh.ts +44 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +79 -9
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +45 -9
- package/src/deploy/platforms/netlify.ts +35 -2
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +149 -17
- package/src/deploy/redirects.ts +151 -24
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +326 -102
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/relative-links.ts +3 -2
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +7 -6
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +72 -27
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +182 -4
- package/src/openapi/references.ts +64 -8
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +40 -15
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +247 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +60 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +20 -3
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +80 -8
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +23 -5
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +191 -34
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +111 -10
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +76 -26
- package/src/seo/metatags.ts +67 -0
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/shared.ts +3 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +85 -6
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +31 -3
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
- package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
- package/dist/cli/chunk-35d4wj9f.js.map +0 -15
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-8ktnccpt.js.map +0 -10
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-b07cmahc.js +0 -145
- package/dist/cli/chunk-b07cmahc.js.map +0 -11
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-e04dxsz1.js +0 -39
- package/dist/cli/chunk-e04dxsz1.js.map +0 -10
- package/dist/cli/chunk-j85vccga.js.map +0 -36
- package/dist/cli/chunk-p3v96n38.js.map +0 -10
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
|
@@ -156,22 +156,31 @@ const ICONS = {
|
|
|
156
156
|
|
|
157
157
|
// --- Frontmatter field policy ----------------------------------------------
|
|
158
158
|
// Top-level keys Blume's strict schema rejects: delete the whole block, report.
|
|
159
|
-
const DROP = new Set([
|
|
160
|
-
"groups",
|
|
161
|
-
"hideApiMarker",
|
|
162
|
-
"hideFooterPagination",
|
|
163
|
-
"iconType",
|
|
164
|
-
"keywords",
|
|
165
|
-
"mode",
|
|
166
|
-
"public",
|
|
167
|
-
"rss",
|
|
168
|
-
]);
|
|
159
|
+
const DROP = new Set(["groups", "hideApiMarker", "iconType", "public", "rss"]);
|
|
169
160
|
|
|
170
|
-
//
|
|
161
|
+
// Keys whose fate depends on their value: the source value (and its line) →
|
|
162
|
+
// the line that replaces it, the line itself to keep it, or `null` to drop it
|
|
163
|
+
// (a value Blume has no counterpart for, or one that restates its default).
|
|
164
|
+
const REPLACE = {
|
|
165
|
+
hideFooterPagination: (value) =>
|
|
166
|
+
value === "true" ? "pagination: false" : null,
|
|
167
|
+
mode: (value, line) => (value === "assistant" ? null : line),
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Mintlify-only keys → Blume nested target. `[parent, child]`, plus a value
|
|
171
|
+
// mapper where the meaning flips: it returns the new value, or `null` to drop a
|
|
172
|
+
// value that restates Blume's default.
|
|
171
173
|
const RENAME = {
|
|
174
|
+
boost: ["search", "boost"],
|
|
172
175
|
canonical: ["seo", "canonical"],
|
|
176
|
+
keywords: ["search", "keywords"],
|
|
173
177
|
"og:image": ["seo", "image"],
|
|
174
178
|
ogImage: ["seo", "image"],
|
|
179
|
+
searchable: [
|
|
180
|
+
"search",
|
|
181
|
+
"exclude",
|
|
182
|
+
(value) => (value === "false" ? "true" : null),
|
|
183
|
+
],
|
|
175
184
|
sidebarTitle: ["sidebar", "label"],
|
|
176
185
|
tag: ["sidebar", "badge"],
|
|
177
186
|
};
|
|
@@ -179,7 +188,8 @@ const RENAME = {
|
|
|
179
188
|
// Keys we deliberately do NOT auto-transform — they usually mean the page is an
|
|
180
189
|
// OpenAPI endpoint stub that should be deleted (Blume generates operation pages),
|
|
181
190
|
// or else a normal page that just loses the key. Flag for the human; never guess.
|
|
182
|
-
|
|
191
|
+
// (`api` is not one: a hand-written endpoint page keeps it as written.)
|
|
192
|
+
const FLAG = new Set(["asyncapi", "openapi"]);
|
|
183
193
|
|
|
184
194
|
// Which change kinds actually edit the file. Report-only kinds (flags,
|
|
185
195
|
// unknowns, conflicts, manual-rename notices) leave the bytes untouched.
|
|
@@ -334,11 +344,41 @@ const rewriteFields = (fm) => {
|
|
|
334
344
|
changes.push({ detail: tk.key, kind: "flag" });
|
|
335
345
|
continue;
|
|
336
346
|
}
|
|
347
|
+
if (Object.hasOwn(REPLACE, tk.key)) {
|
|
348
|
+
const [start, end] = blockRange(fm, i);
|
|
349
|
+
const value = tk.value.replace(
|
|
350
|
+
/^(?<q>["'])(?<inner>.*)\k<q>$/u,
|
|
351
|
+
"$<inner>"
|
|
352
|
+
);
|
|
353
|
+
const line =
|
|
354
|
+
end - start === 1 ? REPLACE[tk.key](value, fm[start]) : undefined;
|
|
355
|
+
if (line === undefined) {
|
|
356
|
+
changes.push({ detail: tk.key, kind: "rename-manual" });
|
|
357
|
+
} else if (line === null) {
|
|
358
|
+
fm.splice(start, 1);
|
|
359
|
+
changes.push({ detail: `${tk.key}: ${value}`, kind: "drop" });
|
|
360
|
+
} else if (line !== fm[start]) {
|
|
361
|
+
const [key] = line.split(":");
|
|
362
|
+
if (fm.some((other, j) => j !== start && topKey(other)?.key === key)) {
|
|
363
|
+
changes.push({
|
|
364
|
+
detail: `${tk.key} → ${key} (child-exists)`,
|
|
365
|
+
kind: "rename-conflict",
|
|
366
|
+
});
|
|
367
|
+
} else {
|
|
368
|
+
fm[start] = line;
|
|
369
|
+
changes.push({
|
|
370
|
+
detail: `${tk.key}: ${value} → ${line}`,
|
|
371
|
+
kind: "rename",
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
337
377
|
const target = RENAME[tk.key];
|
|
338
378
|
if (!target) {
|
|
339
379
|
continue;
|
|
340
380
|
}
|
|
341
|
-
const [parent, child] = target;
|
|
381
|
+
const [parent, child, map] = target;
|
|
342
382
|
const [start, end] = blockRange(fm, i);
|
|
343
383
|
if (end - start !== 1 || tk.value === "") {
|
|
344
384
|
// Multi-line or valueless source — too structured to move safely.
|
|
@@ -348,12 +388,18 @@ const rewriteFields = (fm) => {
|
|
|
348
388
|
});
|
|
349
389
|
continue;
|
|
350
390
|
}
|
|
391
|
+
const value = map ? map(tk.value) : tk.value;
|
|
392
|
+
if (value === null) {
|
|
393
|
+
fm.splice(start, 1);
|
|
394
|
+
changes.push({ detail: `${tk.key}: ${tk.value}`, kind: "drop" });
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
351
397
|
// Remove the source line before inserting: setNested splices into the
|
|
352
398
|
// parent block, and when that block sits above the source key the insert
|
|
353
399
|
// would otherwise shift `start` onto the wrong line. Failure paths don't
|
|
354
400
|
// mutate `fm`, so the line can be restored as-is on conflict.
|
|
355
401
|
const [removed] = fm.splice(start, 1);
|
|
356
|
-
const placed = setNested(fm, parent, child,
|
|
402
|
+
const placed = setNested(fm, parent, child, value);
|
|
357
403
|
if (placed.ok) {
|
|
358
404
|
if (placed.index < start) {
|
|
359
405
|
// The insert above the cursor pushed the unvisited lines down one
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blume-write-skill
|
|
3
|
+
description: Write the agent skill for a product's Blume docs site — one SKILL.md, grounded in the docs, that teaches a coding agent to use the product (setup, core concepts, common tasks, gotchas) and links each topic's page. Blume publishes it at the site's /skill.md in place of the page map it generates. Use when asked to write, improve, or refresh a docs site's agent skill, or when `blume skill` hands you this task.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Write a docs site's agent skill
|
|
7
|
+
|
|
8
|
+
Every Blume site already publishes a generated skill at `/skill.md`: a map of its pages with their one-line descriptions, built without a model. It tells an agent where things are, not how the product works. Your job is to write the skill that does: what the product is, how to set it up, the concepts and tasks that matter, and where it bites, with every topic linked to the page that covers it.
|
|
9
|
+
|
|
10
|
+
The reader is a coding agent working in someone else's project. It loaded your skill because a task touches this product, and it needs to act correctly without reading the whole site first.
|
|
11
|
+
|
|
12
|
+
## Ground rules
|
|
13
|
+
|
|
14
|
+
- **Only what the docs say.** Every claim, command, config key, flag, environment variable, and code sample must come from a page in the content root, copied rather than paraphrased. Never fill a gap from memory or from what similar products do. Where the docs don't answer something the skill needs, leave it out and list it in your report as a docs gap.
|
|
15
|
+
- **One file.** Keep it a lone `SKILL.md`: no `references/`, `scripts/`, or `assets/`. A single file is what the site serves at `/skill.md` and what an agent can fetch in one request. Depth lives in the docs, so link to them instead of copying them in.
|
|
16
|
+
- **Absolute links to Markdown.** Link pages as `<site><route>.md` (the home page is `<site>/index.md`), using the site URL your prompt gives. Link only pages that exist: a page's route is its path under the content root without the extension, and a folder's `index` page takes the folder's route.
|
|
17
|
+
- **Keep the given name.** The frontmatter `name` must be exactly the one in your prompt. That match is what makes your skill replace the generated one.
|
|
18
|
+
- **Short beats complete.** Aim for well under 300 lines. Skip anything a capable agent already knows (general programming, Markdown, how HTTP works) and anything it can look up from a link when it needs it.
|
|
19
|
+
|
|
20
|
+
## Workflow
|
|
21
|
+
|
|
22
|
+
1. **Read the docs.** Start with `blume.config.ts` (the site's title, description, `content.root`, navigation, API references) and the `meta.ts` files, which give the sidebar order. Then read the home page, the quickstart or installation page, each core-concept page, the configuration reference, the API reference overview, and any troubleshooting or FAQ pages. If the site has been built, its `llms.txt` lists every page with its description.
|
|
23
|
+
|
|
24
|
+
2. **Decide what matters.** Before writing, note:
|
|
25
|
+
- the product in two or three sentences: what it is, who uses it, and how it's installed or reached
|
|
26
|
+
- the five to ten tasks people most often come to the docs to do
|
|
27
|
+
- the concepts an agent must understand to do those tasks right
|
|
28
|
+
- the sharp edges: limits, required setup, defaults that surprise people, common errors, and anything deprecated along with what replaced it
|
|
29
|
+
|
|
30
|
+
3. **Write the skill.** Use this shape, dropping any section the docs give you nothing for:
|
|
31
|
+
|
|
32
|
+
```markdown
|
|
33
|
+
---
|
|
34
|
+
name: <the name from your prompt>
|
|
35
|
+
description: <What the product is and when to use this skill, in the words a user would type: the product name, its package and CLI names, its key concepts. At most 1024 characters.>
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# <Product>
|
|
39
|
+
|
|
40
|
+
<Two or three sentences: what it is, who it's for, how to install or reach it.>
|
|
41
|
+
|
|
42
|
+
## Setup
|
|
43
|
+
|
|
44
|
+
<Install, configure, and authenticate, verbatim from the docs, with a link to the page.>
|
|
45
|
+
|
|
46
|
+
## Core concepts
|
|
47
|
+
|
|
48
|
+
- **<Concept>**: <one line>. [<Page title>](<site><route>.md)
|
|
49
|
+
|
|
50
|
+
## Common tasks
|
|
51
|
+
|
|
52
|
+
### <Task>
|
|
53
|
+
|
|
54
|
+
1. <Step, with the exact command or code from the docs.>
|
|
55
|
+
|
|
56
|
+
See [<Page title>](<site><route>.md).
|
|
57
|
+
|
|
58
|
+
## Gotchas
|
|
59
|
+
|
|
60
|
+
- <The limit, default, or error, and what to do about it.>
|
|
61
|
+
|
|
62
|
+
## Where to look
|
|
63
|
+
|
|
64
|
+
- [<Section>](<site><route>.md): <when to read it>
|
|
65
|
+
- [llms.txt](<site>/llms.txt): every page with a one-line summary.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The `description` decides whether an agent loads the skill at all, so spend time on it. Name the product the way users do, and cover the situations it's for ("setting up X", "calling the X API", "configuring X"). Write the body in the imperative, for an agent that will act on it.
|
|
69
|
+
|
|
70
|
+
If the site serves an MCP server or other agent surfaces, the generated skill names them. Carry those lines over under "Where to look".
|
|
71
|
+
|
|
72
|
+
4. **Check it.**
|
|
73
|
+
- Every link points at a page that exists in the content root, as `<site><route>.md`.
|
|
74
|
+
- Every command, code sample, config key, and default appears in the docs as written.
|
|
75
|
+
- The frontmatter parses, `name` is exactly as given, and `description` is 1024 characters or fewer.
|
|
76
|
+
- Then run the docs build (`blume build`). The build output's `skill.md` should now be yours, and `.well-known/agent-skills/index.json` should list the name once.
|
|
77
|
+
|
|
78
|
+
5. **Report.** Say where you wrote the skill and any config you changed, summarize what it covers, and list the docs gaps you found: questions the skill needed answered that no page does. Those are worth fixing in the docs.
|
|
79
|
+
|
|
80
|
+
## Keeping it current
|
|
81
|
+
|
|
82
|
+
A hand-written skill doesn't update itself the way the generated one does. After a meaningful docs change (new features, renamed APIs, a changed setup flow), run `blume skill` again to refresh it. Update the existing file rather than starting over, and keep what's still true.
|
|
@@ -8,6 +8,7 @@ import { buildRssFeeds } from "../deploy/rss.ts";
|
|
|
8
8
|
import { AI_CATALOG_PATH, hasAiCatalog } from "./ai-catalog.ts";
|
|
9
9
|
import { hasApiCatalog } from "./api-catalog.ts";
|
|
10
10
|
import { API_PAGES_PATH, API_SEARCH_PATH, OPENAPI_PATH } from "./api/paths.ts";
|
|
11
|
+
import { servesSkillsIndex } from "./skills.ts";
|
|
11
12
|
|
|
12
13
|
/** Token map for the machine-readable content-usage echo. */
|
|
13
14
|
const USAGE_TOKENS: [keyof ContentSignalPolicy, string][] = [
|
|
@@ -145,7 +146,7 @@ const wellKnownArtifacts = (
|
|
|
145
146
|
if (hasApiCatalog(config)) {
|
|
146
147
|
artifacts.apiCatalog = abs("/.well-known/api-catalog");
|
|
147
148
|
}
|
|
148
|
-
if (config
|
|
149
|
+
if (servesSkillsIndex(config)) {
|
|
149
150
|
artifacts.agentSkills = abs("/.well-known/agent-skills/index.json");
|
|
150
151
|
}
|
|
151
152
|
return artifacts;
|
package/src/ai/agent-surface.ts
CHANGED
|
@@ -11,7 +11,8 @@ export interface EmittedAgentSurface {
|
|
|
11
11
|
mcp: boolean;
|
|
12
12
|
/**
|
|
13
13
|
* A skills discovery index is served: generated from `agents.skills` (at
|
|
14
|
-
* least one valid skill)
|
|
14
|
+
* least one valid skill) or the site skill (`agents.skillMd`), or shipped
|
|
15
|
+
* by the user in `public/`.
|
|
15
16
|
*/
|
|
16
17
|
skills: boolean;
|
|
17
18
|
}
|
|
@@ -33,12 +34,12 @@ export const servesMcp = (
|
|
|
33
34
|
);
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
|
-
* The config the discovery documents are built from: `agents.mcp
|
|
37
|
-
* `agents.skills` switched off when the build didn't
|
|
38
|
-
* agent-readability.json, the catalogs, and the
|
|
39
|
-
* what is there. A config flag says what was asked
|
|
40
|
-
* skipped when a page owns its route, and skills
|
|
41
|
-
* directory is missing or holds no valid skill.
|
|
37
|
+
* The config the discovery documents are built from: `agents.mcp`,
|
|
38
|
+
* `agents.skills`, and `agents.skillMd` switched off when the build didn't
|
|
39
|
+
* emit them, so llms.txt, agent-readability.json, the catalogs, and the
|
|
40
|
+
* header rules only point at what is there. A config flag says what was asked
|
|
41
|
+
* for; the MCP server is skipped when a page owns its route, and skills
|
|
42
|
+
* publish nothing when their directory is missing or holds no valid skill.
|
|
42
43
|
*/
|
|
43
44
|
export const advertisedConfig = (
|
|
44
45
|
config: ResolvedConfig,
|
|
@@ -51,6 +52,7 @@ export const advertisedConfig = (
|
|
|
51
52
|
...config.agents.mcp,
|
|
52
53
|
enabled: config.agents.mcp.enabled && emitted.mcp,
|
|
53
54
|
},
|
|
55
|
+
skillMd: config.agents.skillMd && emitted.skills,
|
|
54
56
|
skills: emitted.skills ? config.agents.skills : undefined,
|
|
55
57
|
},
|
|
56
58
|
});
|
package/src/ai/ai-catalog.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { resolveReferences } from "../openapi/references.ts";
|
|
|
10
10
|
import { API_CATALOG_PATH, hasApiCatalog } from "./api-catalog.ts";
|
|
11
11
|
import { OPENAPI_PATH } from "./api/paths.ts";
|
|
12
12
|
import { asciiSlugify } from "./mcp/discovery.ts";
|
|
13
|
-
import { AGENT_SKILLS_DIR } from "./skills.ts";
|
|
13
|
+
import { AGENT_SKILLS_DIR, servesSkillsIndex } from "./skills.ts";
|
|
14
14
|
import type { SkillArtifact } from "./skills.ts";
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -86,7 +86,7 @@ export const hasAiCatalog = (config: ResolvedConfig): boolean =>
|
|
|
86
86
|
(config.agents.mcp.enabled ||
|
|
87
87
|
config.agents.api ||
|
|
88
88
|
config.agents.llmsTxt.enabled ||
|
|
89
|
-
|
|
89
|
+
servesSkillsIndex(config) ||
|
|
90
90
|
resolveReferences(config).length > 0);
|
|
91
91
|
|
|
92
92
|
/**
|
|
@@ -118,7 +118,10 @@ const NAMES_DOCS = /\b(?:docs|documentation)$/iu;
|
|
|
118
118
|
* reads "the Acme documentation" and "Acme Docs" reads "the Acme Docs", not
|
|
119
119
|
* "the Acme Docs docs".
|
|
120
120
|
*/
|
|
121
|
-
const docsPhrase = (
|
|
121
|
+
export const docsPhrase = (
|
|
122
|
+
title: string,
|
|
123
|
+
noun: "docs" | "documentation"
|
|
124
|
+
): string =>
|
|
122
125
|
NAMES_DOCS.test(title.trim()) ? `the ${title}` : `the ${title} ${noun}`;
|
|
123
126
|
|
|
124
127
|
const entrySeeds = (
|
package/src/ai/ask-context.ts
CHANGED
|
@@ -228,6 +228,17 @@ const queryTerms = (query: string): string[] =>
|
|
|
228
228
|
const BASE_INSTRUCTION =
|
|
229
229
|
"You are a helpful documentation assistant for this project. Answer the user's question using ONLY the documentation excerpts below. Each excerpt is headed by its page as `## Page Title (/route)`. If the answer is not covered by the excerpts, say you don't know and suggest where in the docs to look — do not invent details. Always cite the pages you drew from, and write every citation as a Markdown link to that page using its route, e.g. [Page Title](/route).";
|
|
230
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Appended when the endpoint gives the model the docs tools (see
|
|
233
|
+
* `ask-tools.ts`): the excerpts are a head start, not the whole of the docs.
|
|
234
|
+
*/
|
|
235
|
+
const TOOL_INSTRUCTION =
|
|
236
|
+
"You can also search the documentation yourself. When the excerpts don't fully answer the question, call search_docs with a focused query to find other pages, and read_page to read a page in full (one an excerpt cuts off, say) before you answer. Treat tool results exactly like the excerpts: answer only from them, and cite the pages you drew from the same way.";
|
|
237
|
+
|
|
238
|
+
/** Said instead of the excerpts when retrieval found none but tools can look. */
|
|
239
|
+
const NO_EXCERPTS_WITH_TOOLS =
|
|
240
|
+
"No documentation excerpts matched this question up front. Use search_docs to look before you answer.";
|
|
241
|
+
|
|
231
242
|
/** The non-empty user turns, oldest first. Assistant turns never seed retrieval. */
|
|
232
243
|
const userTurns = (messages: AskMessage[]): string[] =>
|
|
233
244
|
messages
|
|
@@ -591,6 +602,78 @@ export const sectionExcerpt = (
|
|
|
591
602
|
max: number
|
|
592
603
|
): string => excerptPage(parsePage(content), query, max);
|
|
593
604
|
|
|
605
|
+
// One Orama index per snapshot, shared by the grounding function and the
|
|
606
|
+
// docs tools so a cold endpoint builds it once.
|
|
607
|
+
const indexes = new WeakMap<AskData, ReturnType<typeof buildOramaIndex>>();
|
|
608
|
+
|
|
609
|
+
/** The search index over an assistant snapshot, built on first use. */
|
|
610
|
+
export const askIndex = (data: AskData): ReturnType<typeof buildOramaIndex> => {
|
|
611
|
+
let index = indexes.get(data);
|
|
612
|
+
if (!index) {
|
|
613
|
+
index = buildOramaIndex(data.documents, data.defaultLocale);
|
|
614
|
+
indexes.set(data, index);
|
|
615
|
+
}
|
|
616
|
+
return index;
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
/** The page the reader is on, and the search filters it implies. */
|
|
620
|
+
export interface ReaderScope {
|
|
621
|
+
current: OramaDoc | undefined;
|
|
622
|
+
filters: { locale: string | undefined; version: string | undefined };
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// The snapshot's locale codes, keyed lowercase, built once per snapshot.
|
|
626
|
+
const localeCodes = new WeakMap<AskData, Map<string, string>>();
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* The locale a path's first segment names (`/ja` or `/ja/pricing` → `ja`),
|
|
630
|
+
* when it's one the snapshot's documents carry: a page outside the docs,
|
|
631
|
+
* like a localized landing page, still says which language it's in.
|
|
632
|
+
*/
|
|
633
|
+
const pathLocale = (data: AskData, path: string): string | undefined => {
|
|
634
|
+
let codes = localeCodes.get(data);
|
|
635
|
+
if (!codes) {
|
|
636
|
+
codes = new Map<string, string>();
|
|
637
|
+
for (const { locale } of data.documents) {
|
|
638
|
+
if (locale) {
|
|
639
|
+
codes.set(locale.toLowerCase(), locale);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
localeCodes.set(data, codes);
|
|
643
|
+
}
|
|
644
|
+
const [, first = ""] = normalizeRoute(path).split("/");
|
|
645
|
+
return first ? codes.get(first.toLowerCase()) : undefined;
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Where the reader is: their page, when it's in the snapshot, and the locale
|
|
650
|
+
* and docs version retrieval keeps to. A page the snapshot doesn't have (the
|
|
651
|
+
* homepage, a custom page, or none at all from a cross-origin caller) keeps
|
|
652
|
+
* to the locale its path's first segment names, or the default locale, so
|
|
653
|
+
* translations of every page don't crowd each other out. Without a page, a
|
|
654
|
+
* versioned site grounds in the current docs rather than every archived copy
|
|
655
|
+
* of each page.
|
|
656
|
+
*/
|
|
657
|
+
export const readerScope = (
|
|
658
|
+
data: AskData,
|
|
659
|
+
byRoute: ReadonlyMap<string, OramaDoc>,
|
|
660
|
+
page?: AskPage
|
|
661
|
+
): ReaderScope => {
|
|
662
|
+
const current = page?.path
|
|
663
|
+
? byRoute.get(normalizeRoute(page.path))
|
|
664
|
+
: undefined;
|
|
665
|
+
const locale = current
|
|
666
|
+
? current.locale
|
|
667
|
+
: (page?.path && pathLocale(data, page.path)) || data.defaultLocale;
|
|
668
|
+
return {
|
|
669
|
+
current,
|
|
670
|
+
filters: {
|
|
671
|
+
locale: locale || undefined,
|
|
672
|
+
version: data.versioned ? (current?.version ?? "") : undefined,
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
};
|
|
676
|
+
|
|
594
677
|
/**
|
|
595
678
|
* Build the request-time grounding function for the assistant endpoint.
|
|
596
679
|
*
|
|
@@ -607,20 +690,22 @@ export const sectionExcerpt = (
|
|
|
607
690
|
*
|
|
608
691
|
* `options.retrieval` (the `ai.assistant.retrieval` config) sizes how much
|
|
609
692
|
* documentation each question carries; omitted fields keep today's defaults.
|
|
693
|
+
*
|
|
694
|
+
* `options.tools` says the endpoint also hands the model the docs tools: the
|
|
695
|
+
* prompt then says so, and a question retrieval found nothing for still gets
|
|
696
|
+
* a grounded prompt, since the model can go and search.
|
|
610
697
|
*/
|
|
611
698
|
export const createAskContext = (
|
|
612
699
|
data: AskData,
|
|
613
|
-
options?: {
|
|
700
|
+
options?: {
|
|
701
|
+
instructions?: string;
|
|
702
|
+
retrieval?: AskRetrievalOptions;
|
|
703
|
+
tools?: boolean;
|
|
704
|
+
}
|
|
614
705
|
): ((
|
|
615
706
|
messages: AskMessage[],
|
|
616
707
|
page?: AskPage
|
|
617
708
|
) => Promise<string | undefined>) => {
|
|
618
|
-
let dbPromise: Promise<Awaited<ReturnType<typeof buildOramaIndex>>> | null =
|
|
619
|
-
null;
|
|
620
|
-
const index = () => {
|
|
621
|
-
dbPromise ??= buildOramaIndex(data.documents, data.defaultLocale);
|
|
622
|
-
return dbPromise;
|
|
623
|
-
};
|
|
624
709
|
const byRoute = new Map(data.documents.map((doc) => [doc.route, doc]));
|
|
625
710
|
// Section splitting and tokenizing are per page, not per question, so each
|
|
626
711
|
// page is parsed on first use and reused for the life of the endpoint.
|
|
@@ -633,9 +718,12 @@ export const createAskContext = (
|
|
|
633
718
|
}
|
|
634
719
|
return page;
|
|
635
720
|
};
|
|
636
|
-
const
|
|
637
|
-
? `${BASE_INSTRUCTION}
|
|
721
|
+
const base = options?.tools
|
|
722
|
+
? `${BASE_INSTRUCTION} ${TOOL_INSTRUCTION}`
|
|
638
723
|
: BASE_INSTRUCTION;
|
|
724
|
+
const instruction = options?.instructions
|
|
725
|
+
? `${base}\n\n${options.instructions}`
|
|
726
|
+
: base;
|
|
639
727
|
const maxResults = options?.retrieval?.maxResults ?? MAX_RESULTS;
|
|
640
728
|
const excerptChars = options?.retrieval?.excerptChars ?? EXCERPT_CHARS;
|
|
641
729
|
const contextBudget = options?.retrieval?.contextBudget ?? CONTEXT_BUDGET;
|
|
@@ -652,16 +740,9 @@ export const createAskContext = (
|
|
|
652
740
|
const [query = ""] = queries;
|
|
653
741
|
|
|
654
742
|
// The current page anchors retrieval to its locale and docs version, and
|
|
655
|
-
// is injected first.
|
|
656
|
-
|
|
657
|
-
const
|
|
658
|
-
? byRoute.get(normalizeRoute(page.path))
|
|
659
|
-
: undefined;
|
|
660
|
-
const db = await index();
|
|
661
|
-
const filters = {
|
|
662
|
-
locale: current?.locale || undefined,
|
|
663
|
-
version: data.versioned ? (current?.version ?? "") : undefined,
|
|
664
|
-
};
|
|
743
|
+
// is injected first.
|
|
744
|
+
const { current, filters } = readerScope(data, byRoute, page);
|
|
745
|
+
const db = await askIndex(data);
|
|
665
746
|
const hits = interleave(
|
|
666
747
|
await Promise.all(
|
|
667
748
|
queries.map((text) => queryOramaIndex(db, text, maxResults, filters))
|
|
@@ -700,7 +781,9 @@ export const createAskContext = (
|
|
|
700
781
|
}
|
|
701
782
|
|
|
702
783
|
if (sections.length === 0) {
|
|
703
|
-
return
|
|
784
|
+
return options?.tools
|
|
785
|
+
? `${instruction}\n\n${NO_EXCERPTS_WITH_TOOLS}`
|
|
786
|
+
: undefined;
|
|
704
787
|
}
|
|
705
788
|
return `${instruction}\n\n<docs>\n${sections.join("\n\n")}\n</docs>`;
|
|
706
789
|
};
|
package/src/ai/ask-data.ts
CHANGED
|
@@ -36,6 +36,12 @@ export const buildAskData = async (project: BlumeProject): Promise<AskData> => {
|
|
|
36
36
|
if (versioned) {
|
|
37
37
|
document.version = doc.version;
|
|
38
38
|
}
|
|
39
|
+
if (doc.boost !== undefined) {
|
|
40
|
+
document.boost = doc.boost;
|
|
41
|
+
}
|
|
42
|
+
if (doc.keywords) {
|
|
43
|
+
document.keywords = doc.keywords;
|
|
44
|
+
}
|
|
39
45
|
return document;
|
|
40
46
|
}),
|
|
41
47
|
site: project.config.deployment.options.site ?? null,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one request to the assistant's generated route (`/api/ask`) may carry.
|
|
3
|
+
* The route answers a longer conversation with a `400` (see
|
|
4
|
+
* `askEndpointTemplate`), so the panel's client (`useAssistant`) sends only
|
|
5
|
+
* the latest turns that fit. The endpoint is unauthenticated, so the limits
|
|
6
|
+
* bound what one request can spend against the model.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** The most messages, questions and answers together, one request sends. */
|
|
10
|
+
export const ASK_MAX_MESSAGES = 40;
|
|
11
|
+
|
|
12
|
+
/** The most characters the messages take as JSON (`JSON.stringify`). */
|
|
13
|
+
export const ASK_MAX_MESSAGES_CHARS = 24_000;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { jsonSchema, tool } from "ai";
|
|
2
|
+
|
|
3
|
+
import { normalizeRoute } from "../core/base-path.ts";
|
|
4
|
+
import { queryOramaIndex } from "../search/orama-index.ts";
|
|
5
|
+
import type { OramaDoc } from "../search/orama-index.ts";
|
|
6
|
+
import { askIndex, readerScope, sectionExcerpt } from "./ask-context.ts";
|
|
7
|
+
import type { AskData, AskPage, ReaderScope } from "./ask-context.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The assistant's docs tools: what lets it look beyond the excerpts the
|
|
11
|
+
* endpoint injects up front. `search_docs` runs the same Orama search the
|
|
12
|
+
* grounding does, scoped to the reader's language and docs version;
|
|
13
|
+
* `read_page` returns a whole page, for when an excerpt stops short of the
|
|
14
|
+
* answer. Both read the assistant snapshot the endpoint already imports, so
|
|
15
|
+
* they add no build output and no network call.
|
|
16
|
+
*
|
|
17
|
+
* The generated `/api/ask` route passes them to `streamText` with a step cap
|
|
18
|
+
* ({@link ASK_MAX_STEPS}), so the model can search, read, and then answer
|
|
19
|
+
* within one request.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The most model steps one answer may take: up to four rounds of tool calls,
|
|
24
|
+
* then the answer. Enough to search, read a page or two, and search again,
|
|
25
|
+
* while bounding what one question can spend.
|
|
26
|
+
*/
|
|
27
|
+
export const ASK_MAX_STEPS = 5;
|
|
28
|
+
|
|
29
|
+
/** Pages one search returns. */
|
|
30
|
+
const SEARCH_RESULTS = 5;
|
|
31
|
+
|
|
32
|
+
/** Characters of each search result's most relevant excerpt. */
|
|
33
|
+
const SEARCH_EXCERPT_CHARS = 700;
|
|
34
|
+
|
|
35
|
+
/** Characters of a page `read_page` returns; a longer page is cut here. */
|
|
36
|
+
const PAGE_CHARS = 20_000;
|
|
37
|
+
|
|
38
|
+
/** A result block, headed the way the injected excerpts are, for citing. */
|
|
39
|
+
const block = (doc: OramaDoc, body: string): string =>
|
|
40
|
+
`## ${doc.title} (${doc.route})\n${body}`;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Search the docs for `query` within the reader's scope: the most relevant
|
|
44
|
+
* excerpt of each of the top pages, or a note that nothing matched.
|
|
45
|
+
*/
|
|
46
|
+
export const searchDocs = async (
|
|
47
|
+
data: AskData,
|
|
48
|
+
scope: ReaderScope,
|
|
49
|
+
query: string
|
|
50
|
+
): Promise<string> => {
|
|
51
|
+
const hits = await queryOramaIndex(
|
|
52
|
+
await askIndex(data),
|
|
53
|
+
query,
|
|
54
|
+
SEARCH_RESULTS,
|
|
55
|
+
scope.filters
|
|
56
|
+
);
|
|
57
|
+
if (hits.length === 0) {
|
|
58
|
+
return `No pages matched "${query}". Try other words, or a broader query.`;
|
|
59
|
+
}
|
|
60
|
+
return hits
|
|
61
|
+
.map((doc) =>
|
|
62
|
+
block(doc, sectionExcerpt(doc.content, query, SEARCH_EXCERPT_CHARS))
|
|
63
|
+
)
|
|
64
|
+
.join("\n\n");
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The route a model asked for, as the snapshot keys it: a full URL on the
|
|
69
|
+
* site becomes its path, and a query string or fragment is dropped.
|
|
70
|
+
*/
|
|
71
|
+
const routeOf = (data: AskData, requested: string): string => {
|
|
72
|
+
let path = requested.trim();
|
|
73
|
+
if (data.site && path.startsWith(data.site)) {
|
|
74
|
+
path = path.slice(data.site.replace(/\/$/u, "").length) || "/";
|
|
75
|
+
}
|
|
76
|
+
path = path.replace(/[?#].*$/u, "");
|
|
77
|
+
return normalizeRoute(path.startsWith("/") ? path : `/${path}`);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** A whole page by route, cut at {@link PAGE_CHARS}, or a note that it doesn't exist. */
|
|
81
|
+
export const readPage = (
|
|
82
|
+
data: AskData,
|
|
83
|
+
byRoute: ReadonlyMap<string, OramaDoc>,
|
|
84
|
+
requested: string
|
|
85
|
+
): string => {
|
|
86
|
+
const route = routeOf(data, requested);
|
|
87
|
+
const doc = byRoute.get(route);
|
|
88
|
+
if (!doc) {
|
|
89
|
+
return `There is no page at ${route}. Use search_docs to find the right one.`;
|
|
90
|
+
}
|
|
91
|
+
const text =
|
|
92
|
+
doc.content.length > PAGE_CHARS
|
|
93
|
+
? `${doc.content.slice(0, PAGE_CHARS)}\n\n[The page continues; this is its first ${PAGE_CHARS.toLocaleString("en-US")} characters.]`
|
|
94
|
+
: doc.content;
|
|
95
|
+
return block(doc, text);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The tools for one request, given the page the reader is on. Built per
|
|
100
|
+
* request because the search scope follows the reader's locale and version.
|
|
101
|
+
*/
|
|
102
|
+
export const createAskTools = (data: AskData) => {
|
|
103
|
+
const byRoute = new Map(data.documents.map((doc) => [doc.route, doc]));
|
|
104
|
+
return (page?: AskPage) => {
|
|
105
|
+
const scope = readerScope(data, byRoute, page);
|
|
106
|
+
return {
|
|
107
|
+
read_page: tool({
|
|
108
|
+
description:
|
|
109
|
+
"Read one documentation page in full, by its route (the path in parentheses after a page title, such as /docs/getting-started).",
|
|
110
|
+
execute: ({ route }) => Promise.resolve(readPage(data, byRoute, route)),
|
|
111
|
+
inputSchema: jsonSchema<{ route: string }>({
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
properties: {
|
|
114
|
+
route: {
|
|
115
|
+
description: "The page's route, such as /docs/getting-started.",
|
|
116
|
+
type: "string",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ["route"],
|
|
120
|
+
type: "object",
|
|
121
|
+
}),
|
|
122
|
+
}),
|
|
123
|
+
search_docs: tool({
|
|
124
|
+
description:
|
|
125
|
+
"Search this project's documentation. Returns the most relevant excerpt of each matching page, headed by its title and route.",
|
|
126
|
+
execute: ({ query }) => searchDocs(data, scope, query),
|
|
127
|
+
inputSchema: jsonSchema<{ query: string }>({
|
|
128
|
+
additionalProperties: false,
|
|
129
|
+
properties: {
|
|
130
|
+
query: {
|
|
131
|
+
description:
|
|
132
|
+
"A few focused keywords, such as the feature or option the question is about.",
|
|
133
|
+
type: "string",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
required: ["query"],
|
|
137
|
+
type: "object",
|
|
138
|
+
}),
|
|
139
|
+
}),
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
};
|