blume 2.0.2 → 2.1.0
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 +113 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-6k4ftwze.js → chunk-0gz36akr.js} +18 -2
- package/dist/cli/{chunk-6k4ftwze.js.map → chunk-0gz36akr.js.map} +3 -3
- package/dist/cli/{chunk-zp79m0ts.js → chunk-1n228xqb.js} +2 -2
- package/dist/cli/{chunk-ddndchfr.js → chunk-2f3ndkpw.js} +57 -29
- package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
- package/dist/cli/{chunk-fsmrqk8a.js → chunk-2f7n4qzt.js} +8 -2
- package/dist/cli/{chunk-fsmrqk8a.js.map → chunk-2f7n4qzt.js.map} +3 -3
- package/dist/cli/{chunk-ppzjqwx2.js → chunk-2n4ps1b3.js} +17 -18
- package/dist/cli/{chunk-ppzjqwx2.js.map → chunk-2n4ps1b3.js.map} +3 -3
- package/dist/cli/{chunk-5r8g91qn.js → chunk-43zcf4gz.js} +398 -159
- package/dist/cli/chunk-43zcf4gz.js.map +36 -0
- package/dist/cli/chunk-4ejxbzee.js +39 -0
- package/dist/cli/chunk-4ejxbzee.js.map +10 -0
- package/dist/cli/{chunk-hr8ne106.js → chunk-4h8z9vv5.js} +296 -77
- package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
- package/dist/cli/{chunk-k7pj68a8.js → chunk-5cg2rzgf.js} +18 -16
- package/dist/cli/{chunk-k7pj68a8.js.map → chunk-5cg2rzgf.js.map} +2 -2
- package/dist/cli/{chunk-h2ez8dzb.js → chunk-5ffywsmb.js} +4 -4
- package/dist/cli/{chunk-g698a744.js → chunk-5wj2qwn2.js} +5 -5
- package/dist/cli/chunk-6bm0xpgd.js +18 -0
- package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
- package/dist/cli/{chunk-3yce002v.js → chunk-713mngdq.js} +15 -8
- package/dist/cli/chunk-713mngdq.js.map +14 -0
- package/dist/cli/{chunk-91ws1n6j.js → chunk-9geymqns.js} +17 -15
- package/dist/cli/{chunk-91ws1n6j.js.map → chunk-9geymqns.js.map} +2 -2
- package/dist/cli/{chunk-6dtt0zfn.js → chunk-9xr4dgee.js} +27 -18
- package/dist/cli/chunk-9xr4dgee.js.map +10 -0
- package/dist/cli/{chunk-sqw4ekg1.js → chunk-amrb6hgh.js} +2 -2
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-wdrt2k2v.js → chunk-cmtcnh9f.js} +90 -26
- package/dist/cli/chunk-cmtcnh9f.js.map +10 -0
- package/dist/cli/chunk-cy5bm0j0.js +104 -0
- package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
- package/dist/cli/{chunk-7mbqtmgb.js → chunk-e7vvk5ya.js} +21 -12
- package/dist/cli/chunk-e7vvk5ya.js.map +10 -0
- package/dist/cli/{chunk-qkb5a8sa.js → chunk-g2z9x01v.js} +6 -98
- package/dist/cli/chunk-g2z9x01v.js.map +10 -0
- package/dist/cli/{chunk-273ygyr4.js → chunk-ga0pf4aj.js} +7 -7
- package/dist/cli/{chunk-273ygyr4.js.map → chunk-ga0pf4aj.js.map} +3 -3
- package/dist/cli/{chunk-h7k3nq3v.js → chunk-gp84za0h.js} +2 -2
- package/dist/cli/{chunk-hqp2ajnh.js → chunk-h2a48yhd.js} +195 -73
- package/dist/cli/chunk-h2a48yhd.js.map +36 -0
- package/dist/cli/{chunk-pbg5a4s3.js → chunk-jnwj5kjj.js} +71 -47
- package/dist/cli/chunk-jnwj5kjj.js.map +19 -0
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-8g8ytmgx.js → chunk-nd1821sk.js} +21 -19
- package/dist/cli/{chunk-8g8ytmgx.js.map → chunk-nd1821sk.js.map} +2 -2
- package/dist/cli/{chunk-w4bxdvsa.js → chunk-ntv4qrt7.js} +17 -15
- package/dist/cli/{chunk-w4bxdvsa.js.map → chunk-ntv4qrt7.js.map} +2 -2
- package/dist/cli/{chunk-bfwp9vp6.js → chunk-p804f3pe.js} +7 -7
- package/dist/cli/{chunk-4e9b9ra6.js → chunk-py62fewh.js} +6 -6
- package/dist/cli/{chunk-4e9b9ra6.js.map → chunk-py62fewh.js.map} +1 -1
- package/dist/cli/chunk-q3wxxq39.js +126 -0
- package/dist/cli/chunk-q3wxxq39.js.map +11 -0
- package/dist/cli/{chunk-j85scx15.js → chunk-rekqz4qg.js} +142 -46
- package/dist/cli/chunk-rekqz4qg.js.map +10 -0
- package/dist/cli/{chunk-00gs3wqs.js → chunk-ta27feev.js} +1 -1
- package/dist/cli/{chunk-v6ya5kcb.js → chunk-xkz5xbtv.js} +4031 -1132
- package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
- package/dist/cli/{chunk-bbnwccaz.js → chunk-y4ykbark.js} +2 -2
- package/dist/cli/{chunk-n1yg3tj3.js → chunk-y5h4r2y0.js} +6 -6
- package/dist/cli/{chunk-n1yg3tj3.js.map → chunk-y5h4r2y0.js.map} +3 -3
- package/dist/cli/{chunk-nfcyttvj.js → chunk-yj17vs39.js} +9 -9
- package/dist/cli/{chunk-nfcyttvj.js.map → chunk-yj17vs39.js.map} +1 -1
- package/dist/cli/{chunk-7vtckvaw.js → chunk-yxmk4pec.js} +16 -14
- package/dist/cli/{chunk-7vtckvaw.js.map → chunk-yxmk4pec.js.map} +2 -2
- package/dist/cli/{chunk-gs7r695n.js → chunk-zccbjcj0.js} +22 -8
- package/dist/cli/{chunk-gs7r695n.js.map → chunk-zccbjcj0.js.map} +3 -3
- package/dist/cli/{chunk-xh43dwgw.js → chunk-zf748avv.js} +415 -225
- package/dist/cli/chunk-zf748avv.js.map +37 -0
- package/dist/cli/{chunk-d1v5rhy0.js → chunk-zhvd6adm.js} +16 -14
- package/dist/cli/{chunk-d1v5rhy0.js.map → chunk-zhvd6adm.js.map} +2 -2
- package/dist/cli/index.js +28 -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 +22 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +9 -7
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +20 -1
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- package/dist/types/astro/integration.d.ts +11 -2
- 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/components/content/api-field.d.ts +59 -0
- package/dist/types/components/content/api-page.d.ts +95 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/helpers.d.ts +137 -0
- package/dist/types/components/openapi/security.d.ts +85 -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/base-path.d.ts +21 -7
- package/dist/types/core/config-input.d.ts +196 -27
- package/dist/types/core/data.d.ts +49 -4
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +86 -0
- package/dist/types/core/i18n.d.ts +2 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/meta.d.ts +8 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/redirect-patterns.d.ts +144 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +558 -56
- package/dist/types/core/sources/lower.d.ts +29 -16
- package/dist/types/core/sources/normalize.d.ts +13 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/core/types.d.ts +1 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/headers.d.ts +5 -0
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/types.d.ts +8 -0
- package/dist/types/deploy/platforms/vercel.d.ts +6 -0
- package/dist/types/deploy/redirects.d.ts +61 -22
- package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +24 -2
- package/dist/types/markdown/mdast.d.ts +63 -0
- 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/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +12 -6
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +13 -0
- package/dist/types/openapi/references.d.ts +14 -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 +111 -0
- package/dist/types/ratelimit/upstash.d.ts +21 -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 +13 -10
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +45 -5
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +60 -36
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +4 -0
- package/dist/types/seo/metatags.d.ts +20 -0
- package/docs/02-deployment.mdx +44 -6
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/08-faq.mdx +1 -1
- package/docs/advanced/changelog.mdx +2 -2
- package/docs/advanced/custom-pages.mdx +3 -3
- package/docs/advanced/skills.mdx +14 -0
- package/docs/cli/audit.mdx +38 -2
- package/docs/cli/evals.mdx +3 -3
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +3 -3
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +22 -1
- package/docs/configuration/assistant.mdx +188 -36
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +6 -4
- package/docs/configuration/index.mdx +63 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +69 -0
- package/docs/configuration/search.mdx +30 -2
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +107 -1
- package/docs/content/frontmatter.mdx +77 -1
- package/docs/content/i18n.mdx +40 -3
- package/docs/content/includes.mdx +16 -0
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +4 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +28 -6
- package/docs/content/sources/contentful.mdx +32 -0
- package/docs/content/sources/custom.mdx +39 -0
- package/docs/content/sources/github-releases.mdx +31 -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 +30 -0
- package/docs/content/sources/remote-mdx.mdx +40 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +31 -0
- package/docs/content/syntax.mdx +81 -2
- package/docs/content/variables.mdx +41 -0
- package/docs/content/versioning.mdx +1 -1
- package/docs/discoverability/agent-discovery.mdx +30 -3
- package/docs/discoverability/index.mdx +3 -2
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +2 -2
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/open-graph.mdx +5 -3
- package/docs/discoverability/rss.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +3 -3
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +106 -5
- package/docs/references/scalar.mdx +3 -1
- package/package.json +36 -1
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +5 -5
- package/skills/blume-migrate/references/docusaurus.md +3 -3
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +3 -3
- package/skills/blume-migrate/references/starlight.md +2 -1
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +67 -16
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +4 -3
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +12 -5
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +2 -2
- package/src/ai/api-catalog.ts +6 -2
- package/src/ai/ask-context.ts +73 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +75 -0
- package/src/ai/cors.ts +2 -0
- package/src/ai/index.ts +12 -0
- package/src/ai/link-headers.ts +14 -5
- package/src/ai/llms.ts +24 -9
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +2 -2
- package/src/ai/openapi-components.ts +31 -9
- package/src/ai/relative-links.ts +42 -26
- package/src/ai/serializers.ts +2 -1
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +49 -3
- package/src/ai/tar.ts +139 -12
- package/src/ai/write-skill.ts +97 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +5 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +133 -19
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +143 -14
- package/src/astro/module-types.ts +6 -0
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +364 -67
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +19 -0
- 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 +13 -13
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/graph.ts +3 -1
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +14 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +2 -1
- package/src/blume-modules.d.ts +7 -0
- 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 +32 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +4 -1
- package/src/cli/commands/doctor.ts +25 -17
- package/src/cli/commands/eval.ts +19 -11
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/translate.ts +9 -12
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/index.ts +5 -0
- package/src/cli/report-format.ts +11 -6
- package/src/cli/required-secrets.ts +71 -29
- package/src/components/BlumePage.astro +2 -0
- package/src/components/colors.ts +19 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +62 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Badge.astro +5 -3
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/Component.astro +2 -2
- 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/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +4 -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 +100 -0
- package/src/components/content/api-page.ts +224 -0
- package/src/components/content/badge-color.ts +5 -2
- package/src/components/content/base-href.ts +13 -36
- 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 +125 -18
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +145 -40
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/islands/webmcp.ts +4 -2
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +11 -4
- 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/DiscoveryLinks.astro +9 -5
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +124 -82
- package/src/components/layout/LanguageSwitcher.astro +50 -17
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +35 -9
- package/src/components/layout/NavTabMenu.astro +3 -3
- package/src/components/layout/NavTree.astro +16 -6
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +78 -9
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +313 -50
- package/src/components/layout/Search.astro +64 -30
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +12 -0
- 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/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/analytics.ts +98 -0
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/types.ts +20 -0
- package/src/components/layout/search/typesense.ts +5 -1
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/Operation.astro +163 -13
- package/src/components/openapi/Playground.astro +4 -4
- package/src/components/openapi/RequestBody.astro +6 -4
- package/src/components/openapi/RequestPanel.astro +63 -8
- package/src/components/openapi/Responses.astro +6 -4
- package/src/components/openapi/SchemaTable.astro +7 -0
- package/src/components/openapi/async-snippets.ts +4 -4
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/helpers.ts +19 -9
- package/src/components/openapi/message-composer.ts +6 -1
- package/src/components/openapi/message.ts +17 -2
- package/src/components/openapi/operation-model.ts +81 -11
- package/src/components/openapi/panel.ts +4 -2
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +73 -16
- package/src/components/openapi/request.ts +190 -26
- package/src/components/openapi/schema-tree.ts +30 -24
- package/src/components/openapi/security.ts +6 -3
- package/src/components/openapi/snippets.ts +953 -13
- package/src/components/openapi/ws-client.ts +18 -2
- 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/base-path.ts +62 -16
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/client-address.ts +19 -0
- package/src/core/config-input.ts +203 -27
- package/src/core/data.ts +44 -4
- package/src/core/diagnostics.ts +5 -2
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/footer.ts +26 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +39 -36
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +82 -2
- package/src/core/i18n.ts +31 -3
- package/src/core/includes.ts +20 -3
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +16 -2
- package/src/core/locale-links.ts +5 -1
- package/src/core/localizable.ts +26 -0
- package/src/core/meta.ts +33 -19
- package/src/core/navigation.ts +71 -20
- package/src/core/page-modes.ts +56 -0
- package/src/core/project-graph.ts +138 -10
- package/src/core/redirect-patterns.ts +491 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +342 -68
- package/src/core/sources/contentful-rich-text.ts +27 -20
- package/src/core/sources/filesystem.ts +20 -2
- package/src/core/sources/github-releases.ts +25 -6
- package/src/core/sources/lexical.ts +23 -18
- package/src/core/sources/lower.ts +201 -34
- package/src/core/sources/mdx-remote.ts +51 -16
- package/src/core/sources/normalize.ts +327 -91
- package/src/core/sources/notion.ts +52 -25
- package/src/core/sources/obsidian.ts +23 -6
- package/src/core/sources/portable-text.ts +38 -21
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/strapi-blocks.ts +20 -16
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +1 -1
- package/src/core/ui-packs/ar.ts +43 -0
- package/src/core/ui-packs/bg.ts +45 -0
- package/src/core/ui-packs/bn.ts +43 -0
- package/src/core/ui-packs/ca.ts +46 -0
- package/src/core/ui-packs/cs.ts +44 -0
- package/src/core/ui-packs/da.ts +45 -0
- package/src/core/ui-packs/de.ts +46 -0
- package/src/core/ui-packs/el.ts +45 -0
- package/src/core/ui-packs/es.ts +46 -0
- package/src/core/ui-packs/fa.ts +45 -0
- package/src/core/ui-packs/fi.ts +45 -0
- package/src/core/ui-packs/fr.ts +46 -0
- package/src/core/ui-packs/he.ts +43 -0
- package/src/core/ui-packs/hi.ts +44 -0
- package/src/core/ui-packs/hr.ts +45 -0
- package/src/core/ui-packs/hu.ts +44 -0
- package/src/core/ui-packs/id.ts +45 -0
- package/src/core/ui-packs/it.ts +45 -0
- package/src/core/ui-packs/ja.ts +45 -0
- package/src/core/ui-packs/ko.ts +44 -0
- package/src/core/ui-packs/nl.ts +46 -0
- package/src/core/ui-packs/no.ts +44 -0
- package/src/core/ui-packs/pl.ts +45 -0
- package/src/core/ui-packs/pt-br.ts +46 -0
- package/src/core/ui-packs/pt.ts +45 -0
- package/src/core/ui-packs/ro.ts +45 -0
- package/src/core/ui-packs/ru.ts +45 -0
- package/src/core/ui-packs/sk.ts +44 -0
- package/src/core/ui-packs/sr.ts +45 -0
- package/src/core/ui-packs/sv.ts +44 -0
- package/src/core/ui-packs/th.ts +43 -0
- package/src/core/ui-packs/tr.ts +45 -0
- package/src/core/ui-packs/uk.ts +45 -0
- package/src/core/ui-packs/vi.ts +45 -0
- package/src/core/ui-packs/zh-tw.ts +43 -0
- package/src/core/ui-packs/zh.ts +43 -0
- package/src/core/variables.ts +103 -0
- package/src/core/version-cut.ts +52 -15
- package/src/deploy/artifacts.ts +104 -14
- package/src/deploy/cloudflare-negotiation.ts +39 -17
- package/src/deploy/headers.ts +10 -5
- package/src/deploy/node-headers.ts +64 -10
- package/src/deploy/platforms/cloudflare.ts +44 -3
- package/src/deploy/platforms/netlify.ts +34 -1
- package/src/deploy/platforms/node.ts +1 -0
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +8 -0
- package/src/deploy/platforms/vercel.ts +38 -2
- package/src/deploy/redirects.ts +139 -36
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/deploy/vercel-negotiation.ts +36 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/base-links.ts +34 -36
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +20 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +35 -11
- package/src/markdown/math.ts +4 -4
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +12 -4
- 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 +136 -11
- package/src/og/derive.ts +41 -31
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/model.ts +77 -36
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +55 -2
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/references.ts +21 -5
- package/src/openapi/render-mdx.ts +46 -3
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +1 -1
- 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 +229 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +30 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +5 -2
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +51 -7
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +201 -28
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +93 -28
- package/src/search/orama-index.ts +28 -3
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +15 -4
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +5 -0
- package/src/seo/jsonld.ts +7 -3
- package/src/seo/metatags.ts +67 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +56 -3
- package/src/theme/palette.ts +121 -45
- package/src/translate/meta.ts +68 -24
- package/src/translate/prompts.ts +1 -0
- package/src/translate/run.ts +3 -3
- package/src/translate/validate.ts +12 -3
- package/src/translate/work-list.ts +56 -17
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-3yce002v.js.map +0 -14
- package/dist/cli/chunk-5r8g91qn.js.map +0 -34
- package/dist/cli/chunk-6dtt0zfn.js.map +0 -10
- package/dist/cli/chunk-7mbqtmgb.js.map +0 -10
- package/dist/cli/chunk-ddndchfr.js.map +0 -14
- package/dist/cli/chunk-esh98wmb.js +0 -23
- package/dist/cli/chunk-esh98wmb.js.map +0 -10
- package/dist/cli/chunk-hqp2ajnh.js.map +0 -35
- package/dist/cli/chunk-hr8ne106.js.map +0 -13
- package/dist/cli/chunk-j85scx15.js.map +0 -10
- package/dist/cli/chunk-mqc662a6.js +0 -75
- package/dist/cli/chunk-mqc662a6.js.map +0 -11
- package/dist/cli/chunk-pbg5a4s3.js.map +0 -19
- package/dist/cli/chunk-qkb5a8sa.js.map +0 -10
- package/dist/cli/chunk-v6ya5kcb.js.map +0 -189
- package/dist/cli/chunk-wdrt2k2v.js.map +0 -10
- package/dist/cli/chunk-xh43dwgw.js.map +0 -36
- package/docs/content/sources.mdx +0 -338
- /package/dist/cli/{chunk-zp79m0ts.js.map → chunk-1n228xqb.js.map} +0 -0
- /package/dist/cli/{chunk-h2ez8dzb.js.map → chunk-5ffywsmb.js.map} +0 -0
- /package/dist/cli/{chunk-g698a744.js.map → chunk-5wj2qwn2.js.map} +0 -0
- /package/dist/cli/{chunk-sqw4ekg1.js.map → chunk-amrb6hgh.js.map} +0 -0
- /package/dist/cli/{chunk-h7k3nq3v.js.map → chunk-gp84za0h.js.map} +0 -0
- /package/dist/cli/{chunk-bfwp9vp6.js.map → chunk-p804f3pe.js.map} +0 -0
- /package/dist/cli/{chunk-00gs3wqs.js.map → chunk-ta27feev.js.map} +0 -0
- /package/dist/cli/{chunk-bbnwccaz.js.map → chunk-y4ykbark.js.map} +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { hasGeneratedChangelog } from "../astro/pages.ts";
|
|
2
|
+
import {
|
|
3
|
+
mountBasePath,
|
|
4
|
+
normalizeBasePath,
|
|
5
|
+
withBasePath,
|
|
6
|
+
} from "../core/base-path.ts";
|
|
7
|
+
import { CHANGELOG_INDEX_ROUTE } from "../core/changelog-index.ts";
|
|
8
|
+
import { discoverPagesSync } from "../core/custom-pages.ts";
|
|
9
|
+
import type { BlumeProject } from "../core/project-graph.ts";
|
|
10
|
+
import { absoluteUrl } from "../core/site-url.ts";
|
|
11
|
+
import type { NavNode, PageRecord } from "../core/types.ts";
|
|
12
|
+
import { resolveReferences } from "../openapi/references.ts";
|
|
13
|
+
import { docsPhrase } from "./ai-catalog.ts";
|
|
14
|
+
import { API_PAGES_PATH } from "./api/paths.ts";
|
|
15
|
+
import { asciiSlugify } from "./mcp/discovery.ts";
|
|
16
|
+
import {
|
|
17
|
+
SKILL_DESCRIPTION_MAX,
|
|
18
|
+
generatesSiteSkill,
|
|
19
|
+
skillMdArtifact,
|
|
20
|
+
} from "./skills.ts";
|
|
21
|
+
import type { SkillArtifact } from "./skills.ts";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The site's own agent skill (`agents.skillMd`): a `SKILL.md` in the Agent
|
|
25
|
+
* Skills format, built from what the build already knows — the site's title
|
|
26
|
+
* and description, how to read any page as Markdown, llms.txt and the MCP
|
|
27
|
+
* server, the API references, and a map of the docs with each page's one-line
|
|
28
|
+
* description. No model writes it, so it costs nothing and is current with
|
|
29
|
+
* every build: a guide to the docs rather than a summary of the product. A
|
|
30
|
+
* hand-written skill of the same name in `agents.skills` replaces it.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** The most pages the map lists; llms.txt holds the rest. */
|
|
34
|
+
export const MAX_SKILL_PAGES = 200;
|
|
35
|
+
|
|
36
|
+
/** The Agent Skills spec caps a skill name at 64 characters. */
|
|
37
|
+
const NAME_MAX = 64;
|
|
38
|
+
|
|
39
|
+
/** Where the site skill is served besides the discovery index. */
|
|
40
|
+
export const SKILL_MD_PATH = "/skill.md";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The site skill's name: the title as a skill name (lowercase alphanumerics
|
|
44
|
+
* and single hyphens), else the site's host, for a title with no Latin
|
|
45
|
+
* letters in it.
|
|
46
|
+
*/
|
|
47
|
+
export const siteSkillName = (project: BlumeProject): string => {
|
|
48
|
+
const { site } = project.config.deployment.options;
|
|
49
|
+
const fromTitle = asciiSlugify(project.config.title);
|
|
50
|
+
const name =
|
|
51
|
+
fromTitle || asciiSlugify(site ? new URL(site).hostname : "") || "docs";
|
|
52
|
+
return name.slice(0, NAME_MAX).replace(/-+$/u, "");
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** A title as Markdown link text (brackets escaped, as in llms.txt). */
|
|
56
|
+
const linkText = (title: string): string =>
|
|
57
|
+
title.replaceAll(/[\\[\]]/gu, String.raw`\$&`);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Current-version, default-locale pages worth listing: not API operations,
|
|
61
|
+
* and not changelog entries, which the changelog index covers in one line.
|
|
62
|
+
*/
|
|
63
|
+
const mappedPages = (project: BlumeProject): PageRecord[] => {
|
|
64
|
+
const defaultLocale = project.config.i18n?.defaultLocale;
|
|
65
|
+
return project.graph.pages.filter(
|
|
66
|
+
(page) =>
|
|
67
|
+
!(
|
|
68
|
+
page.meta.ai.exclude ||
|
|
69
|
+
page.meta.draft ||
|
|
70
|
+
page.meta.sidebar.hidden ||
|
|
71
|
+
page.meta.seo.noindex ||
|
|
72
|
+
page.version !== "" ||
|
|
73
|
+
page.source.name === "openapi" ||
|
|
74
|
+
page.contentType === "changelog"
|
|
75
|
+
) &&
|
|
76
|
+
(defaultLocale === undefined || page.locale === defaultLocale)
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** Renders the page map, listing each page once, up to the cap. */
|
|
81
|
+
class PageMap {
|
|
82
|
+
readonly #byRoute: Map<string, PageRecord>;
|
|
83
|
+
readonly #listed = new Set<string>();
|
|
84
|
+
readonly #url: (route: string) => string;
|
|
85
|
+
|
|
86
|
+
constructor(pages: PageRecord[], url: (route: string) => string) {
|
|
87
|
+
this.#byRoute = new Map(pages.map((page) => [page.route, page]));
|
|
88
|
+
this.#url = url;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** How many listable pages the cap left out. */
|
|
92
|
+
get omitted(): number {
|
|
93
|
+
return this.#byRoute.size - this.#listed.size;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The Markdown link line for a route, or nothing when it isn't listed. */
|
|
97
|
+
line(route: string): string[] {
|
|
98
|
+
const page = this.#byRoute.get(route);
|
|
99
|
+
if (
|
|
100
|
+
!page ||
|
|
101
|
+
this.#listed.has(route) ||
|
|
102
|
+
this.#listed.size >= MAX_SKILL_PAGES
|
|
103
|
+
) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
this.#listed.add(route);
|
|
107
|
+
const summary = page.description ? `: ${page.description}` : "";
|
|
108
|
+
return [`- [${linkText(page.title)}](${this.#url(route)})${summary}`];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** One navigation level: its loose pages, then each group under a heading. */
|
|
112
|
+
level(nodes: NavNode[], depth: number): string[] {
|
|
113
|
+
const list: string[] = [];
|
|
114
|
+
const groups: string[] = [];
|
|
115
|
+
for (const node of nodes) {
|
|
116
|
+
if (node.kind === "page") {
|
|
117
|
+
list.push(...this.line(node.route));
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const blocks = [
|
|
121
|
+
...(node.route ? this.line(node.route) : []),
|
|
122
|
+
...this.level(node.children, depth + 1),
|
|
123
|
+
];
|
|
124
|
+
if (blocks.length > 0) {
|
|
125
|
+
groups.push(
|
|
126
|
+
"",
|
|
127
|
+
`${"#".repeat(Math.min(depth, 6))} ${node.label}`,
|
|
128
|
+
"",
|
|
129
|
+
...blocks
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return [...list, ...groups];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Pages the navigation doesn't reach, in route order. */
|
|
137
|
+
rest(): string[] {
|
|
138
|
+
return [...this.#byRoute.keys()]
|
|
139
|
+
.toSorted((a, b) => a.localeCompare(b))
|
|
140
|
+
.flatMap((route) => this.line(route));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** The "Reading the docs" bullets: every agent surface the site serves. */
|
|
145
|
+
const surfaceLines = (
|
|
146
|
+
project: BlumeProject,
|
|
147
|
+
url: (path: string) => string
|
|
148
|
+
): string[] => {
|
|
149
|
+
const { agents } = project.config;
|
|
150
|
+
const lines = [
|
|
151
|
+
`- Any page as Markdown: add \`.md\` to its URL (the home page is ${url("/index.md")}). Every page link below already points at the Markdown.`,
|
|
152
|
+
];
|
|
153
|
+
if (agents.llmsTxt.enabled) {
|
|
154
|
+
lines.push(
|
|
155
|
+
`- [llms.txt](${url("/llms.txt")}): every page with a one-line summary.`,
|
|
156
|
+
`- [llms-full.txt](${url("/llms-full.txt")}): every page in one file, for when you need all of it.`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
if (agents.mcp.enabled) {
|
|
160
|
+
lines.push(
|
|
161
|
+
`- MCP server at ${url(agents.mcp.route)}, with \`search_docs\`, \`get_page\`, \`list_pages\`, and \`get_navigation\`. Connect it to search the docs instead of guessing URLs.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
if (agents.api) {
|
|
165
|
+
lines.push(
|
|
166
|
+
`- [JSON API](${url(API_PAGES_PATH)}): the page index, with each page as JSON and Markdown.`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const userPages = project.context.pagesRoot
|
|
170
|
+
? discoverPagesSync(project.context.pagesRoot)
|
|
171
|
+
: [];
|
|
172
|
+
if (hasGeneratedChangelog(project, userPages)) {
|
|
173
|
+
lines.push(
|
|
174
|
+
`- [Changelog](${url(`${CHANGELOG_INDEX_ROUTE}.md`)}): release notes, newest first.`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return lines;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/** The "API reference" bullets, one per rendered reference. */
|
|
181
|
+
const referenceLines = (
|
|
182
|
+
project: BlumeProject,
|
|
183
|
+
url: (path: string) => string
|
|
184
|
+
): string[] =>
|
|
185
|
+
resolveReferences(project.config).map((reference) => {
|
|
186
|
+
// Scalar renders its own page with no Markdown mirror; Blume-rendered
|
|
187
|
+
// references are pages like any other, one per operation.
|
|
188
|
+
const route =
|
|
189
|
+
reference.kind === "scalar"
|
|
190
|
+
? reference.route
|
|
191
|
+
: withBasePath(reference.basePath, reference.route);
|
|
192
|
+
const pages =
|
|
193
|
+
reference.kind === "scalar"
|
|
194
|
+
? ""
|
|
195
|
+
: ", with a page per operation (add `.md` for its Markdown)";
|
|
196
|
+
return `- [${linkText(reference.label)}](${url(route)})${pages}.`;
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
/** The skill's frontmatter `description`: what it's for and when to use it. */
|
|
200
|
+
const skillDescription = (project: BlumeProject): string => {
|
|
201
|
+
const { description, title } = project.config;
|
|
202
|
+
const summary = description ? ` ${description.trim()}` : "";
|
|
203
|
+
return `Read ${docsPhrase(title, "docs")} instead of answering from memory.${summary} Use when a task involves ${title}: how it works, how to set it up or configure it, or its API.`.slice(
|
|
204
|
+
0,
|
|
205
|
+
SKILL_DESCRIPTION_MAX
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/** The site skill's `SKILL.md`. */
|
|
210
|
+
const skillMarkdown = (project: BlumeProject, name: string): string => {
|
|
211
|
+
const { config } = project;
|
|
212
|
+
const { site = "" } = config.deployment.options;
|
|
213
|
+
const base = normalizeBasePath(config.deployment.options.base);
|
|
214
|
+
// Mounted and encoded like llms.txt's links.
|
|
215
|
+
const url = (path: string): string =>
|
|
216
|
+
encodeURI(absoluteUrl(site, mountBasePath(base, path)));
|
|
217
|
+
const markdownUrl = (route: string): string =>
|
|
218
|
+
url(route === "/" ? "/index.md" : `${route}.md`);
|
|
219
|
+
|
|
220
|
+
const map = new PageMap(mappedPages(project), markdownUrl);
|
|
221
|
+
const pages = [
|
|
222
|
+
...map.level(project.graph.navigation.sidebar, 3),
|
|
223
|
+
...map.rest(),
|
|
224
|
+
];
|
|
225
|
+
const { omitted } = map;
|
|
226
|
+
if (omitted > 0) {
|
|
227
|
+
pages.push(
|
|
228
|
+
"",
|
|
229
|
+
config.agents.llmsTxt.enabled
|
|
230
|
+
? `…and ${omitted} more. [llms.txt](${url("/llms.txt")}) lists every page.`
|
|
231
|
+
: `…and ${omitted} more.`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
const references = referenceLines(project, url);
|
|
235
|
+
|
|
236
|
+
return [
|
|
237
|
+
"---",
|
|
238
|
+
`name: ${name}`,
|
|
239
|
+
`description: ${JSON.stringify(skillDescription(project))}`,
|
|
240
|
+
"---",
|
|
241
|
+
"",
|
|
242
|
+
`# ${config.title}`,
|
|
243
|
+
"",
|
|
244
|
+
...(config.description ? [config.description.trim(), ""] : []),
|
|
245
|
+
`This skill points you at ${docsPhrase(config.title, "docs")}, at ${url("/")}. When a task involves ${config.title}, read the relevant page before relying on what you remember: the docs are the source of truth, and they change.`,
|
|
246
|
+
"",
|
|
247
|
+
"## Reading the docs",
|
|
248
|
+
"",
|
|
249
|
+
...surfaceLines(project, url),
|
|
250
|
+
...(references.length > 0
|
|
251
|
+
? ["", "## API reference", "", ...references]
|
|
252
|
+
: []),
|
|
253
|
+
...(pages.length > 0 ? ["", "## Pages", "", ...pages] : []),
|
|
254
|
+
"",
|
|
255
|
+
]
|
|
256
|
+
.join("\n")
|
|
257
|
+
.replaceAll(/\n{3,}/gu, "\n\n");
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* The generated site skill, or `null` when `agents.skillMd` is off or there
|
|
262
|
+
* is no `deployment.site` to make its links absolute.
|
|
263
|
+
*/
|
|
264
|
+
export const buildSiteSkill = (project: BlumeProject): SkillArtifact | null => {
|
|
265
|
+
if (!generatesSiteSkill(project.config)) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
const name = siteSkillName(project);
|
|
269
|
+
return skillMdArtifact(
|
|
270
|
+
name,
|
|
271
|
+
skillDescription(project),
|
|
272
|
+
skillMarkdown(project, name)
|
|
273
|
+
);
|
|
274
|
+
};
|
package/src/ai/skills.ts
CHANGED
|
@@ -29,7 +29,7 @@ const AGENT_SKILLS_SCHEMA =
|
|
|
29
29
|
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
30
30
|
const SKILL_NAME_MAX = 64;
|
|
31
31
|
/** The Agent Skills spec caps `description` at 1024 characters. */
|
|
32
|
-
const
|
|
32
|
+
export const SKILL_DESCRIPTION_MAX = 1024;
|
|
33
33
|
|
|
34
34
|
/** One publishable skill artifact plus its index entry. */
|
|
35
35
|
export interface SkillArtifact {
|
|
@@ -142,7 +142,7 @@ const skillMeta = (raw: string, dirName: string): SkillMetaResult => {
|
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
return {
|
|
145
|
-
meta: { description: description.slice(0,
|
|
145
|
+
meta: { description: description.slice(0, SKILL_DESCRIPTION_MAX), name },
|
|
146
146
|
};
|
|
147
147
|
};
|
|
148
148
|
|
|
@@ -151,11 +151,16 @@ const skillMeta = (raw: string, dirName: string): SkillMetaResult => {
|
|
|
151
151
|
* hold a `SKILL.md` (the layout `npx skills add` consumes). Subdirectories
|
|
152
152
|
* without one are ignored silently — the directory may hold other assets —
|
|
153
153
|
* while a present-but-invalid skill earns a warning so it isn't dropped
|
|
154
|
-
* behind the publisher's back.
|
|
154
|
+
* behind the publisher's back. Two directories declaring the same `name`
|
|
155
|
+
* would publish to the same artifact path under two index entries, so the
|
|
156
|
+
* first directory in sorted order keeps the name and the other is skipped
|
|
157
|
+
* with a warning naming both.
|
|
155
158
|
*/
|
|
156
159
|
export const collectSkills = async (dir: string): Promise<CollectedSkills> => {
|
|
157
160
|
const skills: SkillArtifact[] = [];
|
|
158
161
|
const warnings: string[] = [];
|
|
162
|
+
/** Skill name → the directory that claimed it first. */
|
|
163
|
+
const owners = new Map<string, string>();
|
|
159
164
|
const items = await readdir(dir, { withFileTypes: true });
|
|
160
165
|
for (const item of items.toSorted((a, b) => (a.name < b.name ? -1 : 1))) {
|
|
161
166
|
if (!item.isDirectory() || item.name.startsWith(".")) {
|
|
@@ -177,6 +182,14 @@ export const collectSkills = async (dir: string): Promise<CollectedSkills> => {
|
|
|
177
182
|
}
|
|
178
183
|
continue;
|
|
179
184
|
}
|
|
185
|
+
const owner = owners.get(meta.name);
|
|
186
|
+
if (owner) {
|
|
187
|
+
warnings.push(
|
|
188
|
+
`Skills "${owner}" and "${item.name}" both declare the name "${meta.name}"; publishing "${owner}" and skipping "${item.name}".`
|
|
189
|
+
);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
owners.set(meta.name, item.name);
|
|
180
193
|
// A lone SKILL.md ships verbatim; supporting resources ship as an
|
|
181
194
|
// archive so the skill's relative references resolve after unpacking.
|
|
182
195
|
const single = entries.length === 1;
|
|
@@ -193,6 +206,39 @@ export const collectSkills = async (dir: string): Promise<CollectedSkills> => {
|
|
|
193
206
|
return { skills, warnings };
|
|
194
207
|
};
|
|
195
208
|
|
|
209
|
+
/** A skill that is one `SKILL.md`, published verbatim. */
|
|
210
|
+
export const skillMdArtifact = (
|
|
211
|
+
name: string,
|
|
212
|
+
description: string,
|
|
213
|
+
markdown: string
|
|
214
|
+
): SkillArtifact => {
|
|
215
|
+
const content = new TextEncoder().encode(markdown);
|
|
216
|
+
return {
|
|
217
|
+
content,
|
|
218
|
+
description: description.slice(0, SKILL_DESCRIPTION_MAX),
|
|
219
|
+
digest: sha256(content),
|
|
220
|
+
name,
|
|
221
|
+
path: `${name}/SKILL.md`,
|
|
222
|
+
type: "skill-md",
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Whether the build generates the site's own skill (`agents.skillMd`): on,
|
|
228
|
+
* and with a `deployment.site` to make its links absolute, since an installed
|
|
229
|
+
* skill is read away from the site.
|
|
230
|
+
*/
|
|
231
|
+
export const generatesSiteSkill = (config: ResolvedConfig): boolean =>
|
|
232
|
+
config.agents.skillMd && Boolean(config.deployment.options.site);
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Whether a skills discovery index is served: from `agents.skills`, or for
|
|
236
|
+
* the generated site skill alone. On an advertised config (see
|
|
237
|
+
* `advertisedConfig`), both are already switched off when nothing published.
|
|
238
|
+
*/
|
|
239
|
+
export const servesSkillsIndex = (config: ResolvedConfig): boolean =>
|
|
240
|
+
Boolean(config.agents.skills) || generatesSiteSkill(config);
|
|
241
|
+
|
|
196
242
|
/**
|
|
197
243
|
* The discovery index (v0.2.0 schema). Artifact URLs are path-absolute under
|
|
198
244
|
* `deployment.base` — the RFC resolves them against the index origin.
|
package/src/ai/tar.ts
CHANGED
|
@@ -22,42 +22,169 @@ export interface TarEntry {
|
|
|
22
22
|
path: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/** ustar `name` field capacity
|
|
25
|
+
/** ustar `name` field capacity. */
|
|
26
26
|
const NAME_MAX = 100;
|
|
27
|
+
/** ustar `prefix` field capacity; `prefix/name` reaches 255 bytes. */
|
|
28
|
+
const PREFIX_MAX = 155;
|
|
29
|
+
|
|
30
|
+
/** ustar header byte offsets nanotar leaves for us to patch. */
|
|
31
|
+
const CHECKSUM_OFFSET = 148;
|
|
32
|
+
const CHECKSUM_SIZE = 8;
|
|
33
|
+
const TYPEFLAG_OFFSET = 156;
|
|
34
|
+
const PREFIX_OFFSET = 345;
|
|
35
|
+
const BLOCK_SIZE = 512;
|
|
36
|
+
|
|
37
|
+
/** The two zero blocks that mark the end of an archive. */
|
|
38
|
+
const END_OF_ARCHIVE = 2 * BLOCK_SIZE;
|
|
39
|
+
/** tar's default record size (20 blocks), which the archive is padded to. */
|
|
40
|
+
const RECORD_SIZE = 20 * BLOCK_SIZE;
|
|
41
|
+
|
|
42
|
+
/** The PAX extended-header typeflag (`x`). */
|
|
43
|
+
const PAX_TYPEFLAG = 0x78;
|
|
27
44
|
|
|
28
45
|
const encoder = new TextEncoder();
|
|
29
46
|
|
|
47
|
+
const byteLength = (value: string): number => encoder.encode(value).byteLength;
|
|
48
|
+
|
|
49
|
+
/** `value` cut to at most `max` UTF-8 bytes, on a character boundary. */
|
|
50
|
+
const truncateBytes = (value: string, max: number): string =>
|
|
51
|
+
value.slice(0, encoder.encodeInto(value, new Uint8Array(max)).read);
|
|
52
|
+
|
|
53
|
+
/** One header nanotar writes, plus the fields it cannot. */
|
|
54
|
+
interface Block {
|
|
55
|
+
content: Uint8Array;
|
|
56
|
+
mode: string;
|
|
57
|
+
name: string;
|
|
58
|
+
/** The PAX extended header ahead of an over-long path. */
|
|
59
|
+
pax?: boolean;
|
|
60
|
+
/** ustar `prefix`, joined to `name` with a `/` by readers. */
|
|
61
|
+
prefix?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Split a path over the `name` field at a `/` so the head fits `prefix` and
|
|
66
|
+
* the tail fits `name`. The longest head that fits leaves the shortest tail,
|
|
67
|
+
* so if that tail is still too long no split works.
|
|
68
|
+
*/
|
|
69
|
+
const splitUstar = (
|
|
70
|
+
path: string
|
|
71
|
+
): { name: string; prefix: string } | undefined => {
|
|
72
|
+
let slash = path.lastIndexOf("/");
|
|
73
|
+
while (slash > 0 && byteLength(path.slice(0, slash)) > PREFIX_MAX) {
|
|
74
|
+
slash = path.lastIndexOf("/", slash - 1);
|
|
75
|
+
}
|
|
76
|
+
const name = path.slice(slash + 1);
|
|
77
|
+
if (slash <= 0 || byteLength(name) > NAME_MAX) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return { name, prefix: path.slice(0, slash) };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* A PAX `path` record: `"<length> path=<value>\n"`, where the decimal length
|
|
85
|
+
* counts the whole record including its own digits.
|
|
86
|
+
*/
|
|
87
|
+
const paxPathRecord = (path: string): Uint8Array => {
|
|
88
|
+
const body = ` path=${path}\n`;
|
|
89
|
+
const size = byteLength(body);
|
|
90
|
+
const length = size + String(size + String(size).length).length;
|
|
91
|
+
return encoder.encode(`${length}${body}`);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The header blocks for one entry. A path that fits `name` is written as is;
|
|
96
|
+
* up to 255 bytes it splits across `prefix` and `name`; beyond that (or with
|
|
97
|
+
* no usable split) a PAX extended header carries the full path and the ustar
|
|
98
|
+
* `name` holds a truncated fallback for readers that ignore PAX.
|
|
99
|
+
*/
|
|
100
|
+
const entryBlocks = (entry: TarEntry): Block[] => {
|
|
101
|
+
const mode = entry.executable ? "755" : "644";
|
|
102
|
+
const file = { content: entry.content, mode };
|
|
103
|
+
if (byteLength(entry.path) <= NAME_MAX) {
|
|
104
|
+
return [{ ...file, name: entry.path }];
|
|
105
|
+
}
|
|
106
|
+
const split = splitUstar(entry.path);
|
|
107
|
+
if (split) {
|
|
108
|
+
return [{ ...file, ...split }];
|
|
109
|
+
}
|
|
110
|
+
const base = entry.path.slice(entry.path.lastIndexOf("/") + 1);
|
|
111
|
+
return [
|
|
112
|
+
{
|
|
113
|
+
content: paxPathRecord(entry.path),
|
|
114
|
+
mode: "644",
|
|
115
|
+
name: truncateBytes(`PaxHeader/${base}`, NAME_MAX),
|
|
116
|
+
pax: true,
|
|
117
|
+
},
|
|
118
|
+
{ ...file, name: truncateBytes(base, NAME_MAX) },
|
|
119
|
+
];
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** Recompute a patched header's checksum (nanotar's octal format). */
|
|
123
|
+
const writeChecksum = (header: Uint8Array): void => {
|
|
124
|
+
header.fill(0x20, CHECKSUM_OFFSET, CHECKSUM_OFFSET + CHECKSUM_SIZE);
|
|
125
|
+
const sum = header.reduce((total, byte) => total + byte, 0);
|
|
126
|
+
header.fill(0, CHECKSUM_OFFSET, CHECKSUM_OFFSET + CHECKSUM_SIZE);
|
|
127
|
+
encoder.encodeInto(
|
|
128
|
+
sum.toString(8),
|
|
129
|
+
header.subarray(CHECKSUM_OFFSET, CHECKSUM_OFFSET + CHECKSUM_SIZE)
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
30
133
|
/**
|
|
31
134
|
* Build a gzipped ustar archive of the given files, in the given order. Paths
|
|
32
|
-
*
|
|
33
|
-
* surface a programming error — nanotar would silently truncate an oversized
|
|
34
|
-
* name into a corrupt archive, so the validation stays here.
|
|
135
|
+
* escaping the archive root throw to surface a programming error.
|
|
35
136
|
*/
|
|
36
137
|
export const buildTarGz = (entries: readonly TarEntry[]): Uint8Array => {
|
|
37
138
|
for (const entry of entries) {
|
|
38
|
-
if (encoder.encode(entry.path).byteLength > NAME_MAX) {
|
|
39
|
-
throw new Error(`tar path exceeds ${NAME_MAX} bytes: ${entry.path}`);
|
|
40
|
-
}
|
|
41
139
|
if (entry.path.startsWith("/") || entry.path.split("/").includes("..")) {
|
|
42
140
|
throw new Error(`tar path must be archive-relative: ${entry.path}`);
|
|
43
141
|
}
|
|
44
142
|
}
|
|
143
|
+
const blocks = entries.flatMap(entryBlocks);
|
|
45
144
|
const tar = createTar(
|
|
46
|
-
|
|
145
|
+
blocks.map((block) => ({
|
|
47
146
|
// Root-owned, epoch-mtime, empty owner names: every field a rebuild
|
|
48
147
|
// could vary is pinned so the archive bytes are a function of content.
|
|
49
148
|
attrs: {
|
|
50
149
|
gid: 0,
|
|
51
150
|
group: "",
|
|
52
|
-
mode:
|
|
151
|
+
mode: block.mode,
|
|
53
152
|
mtime: 0,
|
|
54
153
|
uid: 0,
|
|
55
154
|
user: "",
|
|
56
155
|
},
|
|
57
|
-
data:
|
|
58
|
-
name:
|
|
156
|
+
data: block.content,
|
|
157
|
+
name: block.name,
|
|
59
158
|
}))
|
|
60
159
|
);
|
|
160
|
+
// nanotar writes neither `prefix` nor the PAX typeflag, so patch those
|
|
161
|
+
// headers in place and re-sum them.
|
|
162
|
+
let offset = 0;
|
|
163
|
+
for (const block of blocks) {
|
|
164
|
+
const header = tar.subarray(offset, offset + BLOCK_SIZE);
|
|
165
|
+
if (block.prefix) {
|
|
166
|
+
encoder.encodeInto(
|
|
167
|
+
block.prefix,
|
|
168
|
+
header.subarray(PREFIX_OFFSET, PREFIX_OFFSET + PREFIX_MAX)
|
|
169
|
+
);
|
|
170
|
+
writeChecksum(header);
|
|
171
|
+
}
|
|
172
|
+
if (block.pax) {
|
|
173
|
+
header[TYPEFLAG_OFFSET] = PAX_TYPEFLAG;
|
|
174
|
+
writeChecksum(header);
|
|
175
|
+
}
|
|
176
|
+
offset +=
|
|
177
|
+
BLOCK_SIZE * (1 + Math.ceil(block.content.byteLength / BLOCK_SIZE));
|
|
178
|
+
}
|
|
179
|
+
// nanotar pads the entries to a whole record but writes no end-of-archive
|
|
180
|
+
// marker, so entries ending within two blocks of a record boundary leave
|
|
181
|
+
// fewer than the two zero blocks readers expect (GNU tar warns "A lone zero
|
|
182
|
+
// block"). Pad to the first record that fits both; for every other archive
|
|
183
|
+
// that is the size nanotar already wrote, so its bytes are unchanged.
|
|
184
|
+
const archive = new Uint8Array(
|
|
185
|
+
Math.ceil((offset + END_OF_ARCHIVE) / RECORD_SIZE) * RECORD_SIZE
|
|
186
|
+
);
|
|
187
|
+
archive.set(tar.subarray(0, offset));
|
|
61
188
|
// Sync gzip with a pinned level; Node writes no timestamp into the header.
|
|
62
|
-
return new Uint8Array(gzipSync(
|
|
189
|
+
return new Uint8Array(gzipSync(archive, { level: 9 }));
|
|
63
190
|
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { join, relative, resolve } from "pathe";
|
|
4
|
+
|
|
5
|
+
import type { BlumeProject } from "../core/project-graph.ts";
|
|
6
|
+
import { siteSkillName } from "./site-skill.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `blume skill`'s logic, kept out of the command module so it runs (and is
|
|
10
|
+
* covered) in-process. Writing a product skill is judgment work — what the
|
|
11
|
+
* product is, which tasks matter, where it bites — so it lives in the
|
|
12
|
+
* `blume-write-skill` skill, shipped inside the package. This module only
|
|
13
|
+
* works out where the skill goes and writes the prompt that points a coding
|
|
14
|
+
* agent at the skill and the docs.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** The skill's directory inside the published package. */
|
|
18
|
+
export const WRITE_SKILL_DIR = join("skills", "blume-write-skill");
|
|
19
|
+
|
|
20
|
+
/** Where `agents.skills` points when the config doesn't set it. */
|
|
21
|
+
const DEFAULT_SKILLS_DIR = "skills";
|
|
22
|
+
|
|
23
|
+
/** Where the skill goes, and what the agent needs to know to write it. */
|
|
24
|
+
export interface SkillPlan {
|
|
25
|
+
/** The `agents.skills` value to add, when the config has none. */
|
|
26
|
+
configure?: string;
|
|
27
|
+
/** The config file to add it to, relative to the project root. */
|
|
28
|
+
configFile: string;
|
|
29
|
+
/** The content root, relative to the project root. */
|
|
30
|
+
contentRoot: string;
|
|
31
|
+
/** Whether a skill is already there to update. */
|
|
32
|
+
exists: boolean;
|
|
33
|
+
/** Where to write the skill, relative to the project root. */
|
|
34
|
+
file: string;
|
|
35
|
+
/** The skill's name: the generated site skill's, so it replaces it. */
|
|
36
|
+
name: string;
|
|
37
|
+
/** The site's URL, for the skill's absolute links. */
|
|
38
|
+
site?: string;
|
|
39
|
+
title: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Plan the skill for a scanned project. */
|
|
43
|
+
export const planSkill = (project: BlumeProject): SkillPlan => {
|
|
44
|
+
const { config, context } = project;
|
|
45
|
+
const name = siteSkillName(project);
|
|
46
|
+
const file = resolve(
|
|
47
|
+
context.root,
|
|
48
|
+
config.agents.skills ?? DEFAULT_SKILLS_DIR,
|
|
49
|
+
name,
|
|
50
|
+
"SKILL.md"
|
|
51
|
+
);
|
|
52
|
+
const plan: SkillPlan = {
|
|
53
|
+
configFile: context.configFile
|
|
54
|
+
? relative(context.root, context.configFile)
|
|
55
|
+
: "blume.config.ts",
|
|
56
|
+
contentRoot: relative(context.root, context.contentRoot) || ".",
|
|
57
|
+
exists: existsSync(file),
|
|
58
|
+
file: relative(context.root, file),
|
|
59
|
+
name,
|
|
60
|
+
site: config.deployment.options.site,
|
|
61
|
+
title: config.title,
|
|
62
|
+
};
|
|
63
|
+
return config.agents.skills
|
|
64
|
+
? plan
|
|
65
|
+
: { ...plan, configure: `./${DEFAULT_SKILLS_DIR}` };
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** The prompt that hands the plan to a coding agent. */
|
|
69
|
+
export const writeSkillPrompt = (
|
|
70
|
+
plan: SkillPlan,
|
|
71
|
+
options: { skillDir: string; version: string }
|
|
72
|
+
): string => {
|
|
73
|
+
const { skillDir, version } = options;
|
|
74
|
+
const lines = [
|
|
75
|
+
`Write the agent skill for the ${plan.title} docs, a Blume ${version} site.`,
|
|
76
|
+
"",
|
|
77
|
+
`Follow the blume-write-skill skill: read ${join(skillDir, "SKILL.md")} first and work through its workflow.`,
|
|
78
|
+
"",
|
|
79
|
+
plan.exists
|
|
80
|
+
? `A skill already exists at ${plan.file}. Update it against the current docs rather than starting over, and keep what's still true.`
|
|
81
|
+
: `Write it to ${plan.file}.`,
|
|
82
|
+
`Its frontmatter \`name\` must be \`${plan.name}\`: that's the name of the skill Blume generates for this site, and a skill with the same name replaces it.`,
|
|
83
|
+
];
|
|
84
|
+
if (plan.configure) {
|
|
85
|
+
lines.push(
|
|
86
|
+
`Then set \`agents.skills: "${plan.configure}"\` in ${plan.configFile} so the build publishes it.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
lines.push(
|
|
90
|
+
"",
|
|
91
|
+
`The docs source is in ${plan.contentRoot}.`,
|
|
92
|
+
plan.site
|
|
93
|
+
? `The site is served at ${plan.site}, so link pages as ${plan.site.replace(/\/$/u, "")}<route>.md.`
|
|
94
|
+
: `The config has no \`deployment.site\`, and the skill's links must be absolute. Ask me for the site's URL, and set it as \`deployment.site\` in ${plan.configFile}.`
|
|
95
|
+
);
|
|
96
|
+
return lines.join("\n");
|
|
97
|
+
};
|
package/src/analytics/head.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { hightouchHead } from "./hightouch.ts";
|
|
|
12
12
|
import { hotjarHead } from "./hotjar.ts";
|
|
13
13
|
import { logrocketHead } from "./logrocket.ts";
|
|
14
14
|
import { mixpanelHead } from "./mixpanel.ts";
|
|
15
|
+
import { oneDollarStatsHead } from "./one-dollar-stats.ts";
|
|
15
16
|
import { pirschHead } from "./pirsch.ts";
|
|
16
17
|
import { plausibleHead } from "./plausible.ts";
|
|
17
18
|
import { posthogHead } from "./posthog.ts";
|
|
@@ -92,6 +93,9 @@ const adapterScripts = (
|
|
|
92
93
|
case "mixpanel": {
|
|
93
94
|
return mixpanelHead(adapter.options);
|
|
94
95
|
}
|
|
96
|
+
case "one-dollar-stats": {
|
|
97
|
+
return oneDollarStatsHead(adapter.options);
|
|
98
|
+
}
|
|
95
99
|
case "pirsch": {
|
|
96
100
|
return pirschHead(adapter.options);
|
|
97
101
|
}
|
package/src/analytics/index.ts
CHANGED
|
@@ -58,6 +58,11 @@ export type {
|
|
|
58
58
|
MixpanelOptions,
|
|
59
59
|
MixpanelRegion,
|
|
60
60
|
} from "./mixpanel.ts";
|
|
61
|
+
export { oneDollarStats } from "./one-dollar-stats.ts";
|
|
62
|
+
export type {
|
|
63
|
+
OneDollarStatsAdapter,
|
|
64
|
+
OneDollarStatsOptions,
|
|
65
|
+
} from "./one-dollar-stats.ts";
|
|
61
66
|
export { pirsch } from "./pirsch.ts";
|
|
62
67
|
export type { PirschAdapter, PirschOptions } from "./pirsch.ts";
|
|
63
68
|
export { plausible } from "./plausible.ts";
|