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,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser half of the bot check: a fresh token for each question the
|
|
3
|
+
* assistant sends (both providers' tokens are single-use). The provider's
|
|
4
|
+
* script loads with the first question rather than with the page, and one
|
|
5
|
+
* widget serves every question after it: an invisible hCaptcha, or a
|
|
6
|
+
* Turnstile that only shows itself when it needs the reader to interact,
|
|
7
|
+
* in a small container at the foot of the viewport.
|
|
8
|
+
*
|
|
9
|
+
* The client router swaps `<body>` on every navigation, taking the container
|
|
10
|
+
* and its widget with it, so a question after a swap mounts a new one.
|
|
11
|
+
*/
|
|
12
|
+
import type { CaptchaSettings } from "./schema.ts";
|
|
13
|
+
|
|
14
|
+
/** Each provider's script, rendering only when asked to. */
|
|
15
|
+
export const CAPTCHA_SCRIPTS = {
|
|
16
|
+
hcaptcha: "https://js.hcaptcha.com/1/api.js?render=explicit",
|
|
17
|
+
turnstile:
|
|
18
|
+
"https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit",
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
/** What Blume asks a Turnstile widget for. */
|
|
22
|
+
interface TurnstileRenderOptions {
|
|
23
|
+
appearance: "interaction-only";
|
|
24
|
+
callback: (token: string) => void;
|
|
25
|
+
"error-callback": () => void;
|
|
26
|
+
execution: "execute";
|
|
27
|
+
sitekey: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** The slice of `window.turnstile` the check uses. */
|
|
31
|
+
export interface TurnstileApi {
|
|
32
|
+
execute: (widget: string) => void;
|
|
33
|
+
render: (container: HTMLElement, options: TurnstileRenderOptions) => string;
|
|
34
|
+
reset: (widget: string) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** What Blume asks an hCaptcha widget for. */
|
|
38
|
+
interface HcaptchaRenderOptions {
|
|
39
|
+
sitekey: string;
|
|
40
|
+
size: "invisible";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The slice of `window.hcaptcha` the check uses. */
|
|
44
|
+
export interface HcaptchaApi {
|
|
45
|
+
execute: (
|
|
46
|
+
widget: string,
|
|
47
|
+
options: { async: true }
|
|
48
|
+
) => Promise<{ response: string }>;
|
|
49
|
+
render: (container: HTMLElement, options: HcaptchaRenderOptions) => string;
|
|
50
|
+
reset: (widget: string) => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The window, with the providers' globals once their scripts ran. */
|
|
54
|
+
type CaptchaWindow = Window & {
|
|
55
|
+
hcaptcha?: HcaptchaApi;
|
|
56
|
+
turnstile?: TurnstileApi;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** A Turnstile token on its way. */
|
|
60
|
+
interface PendingToken {
|
|
61
|
+
reject: (error: Error) => void;
|
|
62
|
+
resolve: (token: string) => void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Get a token for the next question. */
|
|
66
|
+
export type CaptchaTokenGetter = (settings: CaptchaSettings) => Promise<string>;
|
|
67
|
+
|
|
68
|
+
/** A token getter with its own script, container, and widget. */
|
|
69
|
+
export const createCaptchaClient = (): CaptchaTokenGetter => {
|
|
70
|
+
let loaded: Promise<void> | undefined;
|
|
71
|
+
let host: HTMLElement | undefined;
|
|
72
|
+
let widget: string | undefined;
|
|
73
|
+
let pending: PendingToken | undefined;
|
|
74
|
+
|
|
75
|
+
const load = (kind: CaptchaSettings["kind"]): Promise<void> => {
|
|
76
|
+
// oxlint-disable-next-line promise/avoid-new -- adapt the script tag's load events
|
|
77
|
+
loaded ??= new Promise<void>((resolve, reject) => {
|
|
78
|
+
const tag = document.createElement("script");
|
|
79
|
+
tag.async = true;
|
|
80
|
+
tag.src = CAPTCHA_SCRIPTS[kind];
|
|
81
|
+
tag.addEventListener("load", () => resolve());
|
|
82
|
+
tag.addEventListener("error", () => {
|
|
83
|
+
// Let the next question try again.
|
|
84
|
+
loaded = undefined;
|
|
85
|
+
reject(new Error(`The ${kind} script didn't load.`));
|
|
86
|
+
});
|
|
87
|
+
document.head.append(tag);
|
|
88
|
+
});
|
|
89
|
+
return loaded;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// The widget's container, mounted again when a swap took the last one.
|
|
93
|
+
const mount = (): HTMLElement => {
|
|
94
|
+
if (host?.isConnected) {
|
|
95
|
+
return host;
|
|
96
|
+
}
|
|
97
|
+
host = document.createElement("div");
|
|
98
|
+
host.className = "fixed bottom-4 left-1/2 z-[60] -translate-x-1/2";
|
|
99
|
+
host.dataset.blumeCaptcha = "";
|
|
100
|
+
document.body.append(host);
|
|
101
|
+
widget = undefined;
|
|
102
|
+
return host;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const turnstileToken = (api: TurnstileApi, siteKey: string) =>
|
|
106
|
+
// oxlint-disable-next-line promise/avoid-new -- adapt Turnstile's token callbacks
|
|
107
|
+
new Promise<string>((resolve, reject) => {
|
|
108
|
+
pending = { reject, resolve };
|
|
109
|
+
const target = mount();
|
|
110
|
+
if (widget === undefined) {
|
|
111
|
+
widget = api.render(target, {
|
|
112
|
+
appearance: "interaction-only",
|
|
113
|
+
callback: (token) => pending?.resolve(token),
|
|
114
|
+
"error-callback": () =>
|
|
115
|
+
pending?.reject(new Error("The Turnstile check failed.")),
|
|
116
|
+
execution: "execute",
|
|
117
|
+
sitekey: siteKey,
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
api.reset(widget);
|
|
121
|
+
}
|
|
122
|
+
api.execute(widget);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const hcaptchaToken = async (api: HcaptchaApi, siteKey: string) => {
|
|
126
|
+
const target = mount();
|
|
127
|
+
if (widget === undefined) {
|
|
128
|
+
widget = api.render(target, { sitekey: siteKey, size: "invisible" });
|
|
129
|
+
} else {
|
|
130
|
+
api.reset(widget);
|
|
131
|
+
}
|
|
132
|
+
const { response } = await api.execute(widget, { async: true });
|
|
133
|
+
return response;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return async (settings) => {
|
|
137
|
+
await load(settings.kind);
|
|
138
|
+
// SAFETY: CaptchaWindow only adds the providers' optional globals, each
|
|
139
|
+
// checked before use.
|
|
140
|
+
const { hcaptcha, turnstile } = window as CaptchaWindow;
|
|
141
|
+
if (settings.kind === "hcaptcha" && hcaptcha) {
|
|
142
|
+
return hcaptchaToken(hcaptcha, settings.siteKey);
|
|
143
|
+
}
|
|
144
|
+
if (settings.kind === "turnstile" && turnstile) {
|
|
145
|
+
return turnstileToken(turnstile, settings.siteKey);
|
|
146
|
+
}
|
|
147
|
+
throw new Error(`The ${settings.kind} script loaded without its API.`);
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/** The page's token getter: one script and one widget per page load. */
|
|
152
|
+
export const captchaToken = createCaptchaClient();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { AdapterDescriptor } from "../core/adapter.ts";
|
|
4
|
+
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
5
|
+
|
|
6
|
+
/** Options for {@link hcaptcha}. */
|
|
7
|
+
export interface HcaptchaOptions {
|
|
8
|
+
/** The site key, from the hCaptcha dashboard. */
|
|
9
|
+
siteKey: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const hcaptchaOptionsSchema = z.strictObject({
|
|
13
|
+
siteKey: z.string().min(1),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type HcaptchaAdapter = AdapterDescriptor<"hcaptcha", HcaptchaOptions>;
|
|
17
|
+
|
|
18
|
+
export const hcaptchaAdapterSchema = adapterDescriptorSchema(
|
|
19
|
+
"hcaptcha",
|
|
20
|
+
hcaptchaOptionsSchema
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/** Where the assistant's route checks an hCaptcha token. */
|
|
24
|
+
export const HCAPTCHA_VERIFY_URL = "https://api.hcaptcha.com/siteverify";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* hCaptcha, as an invisible check: most readers never see a challenge. The
|
|
28
|
+
* site key is public and goes to the browser; the secret the route checks
|
|
29
|
+
* tokens with comes from `HCAPTCHA_SECRET_KEY`.
|
|
30
|
+
*/
|
|
31
|
+
export const hcaptcha = (options: HcaptchaOptions): HcaptchaAdapter => ({
|
|
32
|
+
kind: "hcaptcha",
|
|
33
|
+
options,
|
|
34
|
+
requiredSecrets: ["HCAPTCHA_SECRET_KEY"],
|
|
35
|
+
runtimeDeps: [],
|
|
36
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bot checks for the assistant (`ai.assistant.captcha` in `blume.config.ts`).
|
|
3
|
+
* The assistant gets a token from the check before each question and the
|
|
4
|
+
* generated route verifies it before calling the model:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { defineConfig } from "blume";
|
|
8
|
+
* import { turnstile } from "blume/captcha";
|
|
9
|
+
*
|
|
10
|
+
* export default defineConfig({
|
|
11
|
+
* ai: {
|
|
12
|
+
* assistant: {
|
|
13
|
+
* enabled: true,
|
|
14
|
+
* captcha: turnstile({ siteKey: "0x4AAAAAAA…" }),
|
|
15
|
+
* },
|
|
16
|
+
* },
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Each factory returns a plain descriptor (see `core/adapter.ts`); the browser
|
|
21
|
+
* half is `client.ts`, the server half `verify.ts`.
|
|
22
|
+
*/
|
|
23
|
+
export type { AdapterDescriptor, JsonValue } from "../core/adapter.ts";
|
|
24
|
+
export { hcaptcha } from "./hcaptcha.ts";
|
|
25
|
+
export type { HcaptchaAdapter, HcaptchaOptions } from "./hcaptcha.ts";
|
|
26
|
+
export type { CaptchaAdapter, CaptchaSettings } from "./schema.ts";
|
|
27
|
+
export { turnstile } from "./turnstile.ts";
|
|
28
|
+
export type { TurnstileAdapter, TurnstileOptions } from "./turnstile.ts";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { hcaptchaAdapterSchema } from "./hcaptcha.ts";
|
|
4
|
+
import { turnstileAdapterSchema } from "./turnstile.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The configured bot check, as its factory returned it. Anything that isn't
|
|
8
|
+
* one fails with the adapter hint; an adapter's own option errors keep their
|
|
9
|
+
* messages.
|
|
10
|
+
*/
|
|
11
|
+
export const captchaAdapterSchema = z.discriminatedUnion(
|
|
12
|
+
"kind",
|
|
13
|
+
[hcaptchaAdapterSchema, turnstileAdapterSchema],
|
|
14
|
+
{
|
|
15
|
+
error:
|
|
16
|
+
'captcha takes one adapter — e.g. `captcha: turnstile({ siteKey })` or `captcha: hcaptcha({ siteKey })`, imported from "blume/captcha".',
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export type CaptchaAdapter = z.output<typeof captchaAdapterSchema>;
|
|
21
|
+
|
|
22
|
+
/** What the browser needs to run the check: never the secret. */
|
|
23
|
+
export interface CaptchaSettings {
|
|
24
|
+
kind: CaptchaAdapter["kind"];
|
|
25
|
+
siteKey: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The public half of an adapter, for the data snapshot. */
|
|
29
|
+
export const captchaSettings = (adapter: CaptchaAdapter): CaptchaSettings => ({
|
|
30
|
+
kind: adapter.kind,
|
|
31
|
+
siteKey: adapter.options.siteKey,
|
|
32
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { AdapterDescriptor } from "../core/adapter.ts";
|
|
4
|
+
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
5
|
+
|
|
6
|
+
/** Options for {@link turnstile}. */
|
|
7
|
+
export interface TurnstileOptions {
|
|
8
|
+
/** The widget's site key, from the Cloudflare dashboard. */
|
|
9
|
+
siteKey: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const turnstileOptionsSchema = z.strictObject({
|
|
13
|
+
siteKey: z.string().min(1),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type TurnstileAdapter = AdapterDescriptor<"turnstile", TurnstileOptions>;
|
|
17
|
+
|
|
18
|
+
export const turnstileAdapterSchema = adapterDescriptorSchema(
|
|
19
|
+
"turnstile",
|
|
20
|
+
turnstileOptionsSchema
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/** Where the assistant's route checks a Turnstile token. */
|
|
24
|
+
export const TURNSTILE_VERIFY_URL =
|
|
25
|
+
"https://challenges.cloudflare.com/turnstile/v0/siteverify";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Cloudflare Turnstile. The site key is public and goes to the browser; the
|
|
29
|
+
* secret key the route checks tokens with comes from `TURNSTILE_SECRET_KEY`.
|
|
30
|
+
* Set the widget to Invisible or Managed in the Cloudflare dashboard: most
|
|
31
|
+
* readers never see a challenge.
|
|
32
|
+
*/
|
|
33
|
+
export const turnstile = (options: TurnstileOptions): TurnstileAdapter => ({
|
|
34
|
+
kind: "turnstile",
|
|
35
|
+
options,
|
|
36
|
+
requiredSecrets: ["TURNSTILE_SECRET_KEY"],
|
|
37
|
+
runtimeDeps: [],
|
|
38
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server half of the bot check: the generated assistant route verifies
|
|
3
|
+
* the token the browser sent with the question against the provider before
|
|
4
|
+
* it calls the model. A failed or unreachable check refuses the question
|
|
5
|
+
* (and logs why), so a server that can't reach the provider shows up as a
|
|
6
|
+
* refused question rather than a silently unprotected route.
|
|
7
|
+
*/
|
|
8
|
+
import { clientAddressOf } from "../core/client-address.ts";
|
|
9
|
+
import type { ClientContext } from "../core/client-address.ts";
|
|
10
|
+
import { HCAPTCHA_VERIFY_URL } from "./hcaptcha.ts";
|
|
11
|
+
import type { CaptchaAdapter } from "./schema.ts";
|
|
12
|
+
import { TURNSTILE_VERIFY_URL } from "./turnstile.ts";
|
|
13
|
+
|
|
14
|
+
/** The longest token either provider issues, with room to spare. */
|
|
15
|
+
const MAX_TOKEN_LENGTH = 4096;
|
|
16
|
+
|
|
17
|
+
/** What the provider answers about a token. */
|
|
18
|
+
interface VerifyReply {
|
|
19
|
+
"error-codes"?: string[];
|
|
20
|
+
success?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** What the route hands the check from its runtime. */
|
|
24
|
+
export interface VerifyOptions {
|
|
25
|
+
/** For tests; defaults to the global `fetch`. */
|
|
26
|
+
fetch?: typeof fetch;
|
|
27
|
+
/** The provider's secret key. */
|
|
28
|
+
secret: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether the provider confirms `token` came from a person on this site. The
|
|
33
|
+
* route passes the request body's `captcha` when it's a string.
|
|
34
|
+
*/
|
|
35
|
+
export const verifyCaptcha = async (
|
|
36
|
+
adapter: CaptchaAdapter,
|
|
37
|
+
token: string | undefined,
|
|
38
|
+
context: ClientContext,
|
|
39
|
+
options: VerifyOptions
|
|
40
|
+
): Promise<boolean> => {
|
|
41
|
+
if (!token || token.length > MAX_TOKEN_LENGTH) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const form = new URLSearchParams({ response: token, secret: options.secret });
|
|
45
|
+
const address = clientAddressOf(context);
|
|
46
|
+
if (address) {
|
|
47
|
+
form.set("remoteip", address);
|
|
48
|
+
}
|
|
49
|
+
if (adapter.kind === "hcaptcha") {
|
|
50
|
+
form.set("sitekey", adapter.options.siteKey);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const response = await (options.fetch ?? fetch)(
|
|
54
|
+
adapter.kind === "hcaptcha" ? HCAPTCHA_VERIFY_URL : TURNSTILE_VERIFY_URL,
|
|
55
|
+
{ body: form, method: "POST" }
|
|
56
|
+
);
|
|
57
|
+
// SAFETY: both providers answer JSON with a `success` flag; anything
|
|
58
|
+
// else reads as a failure below.
|
|
59
|
+
const reply = (await response.json()) as VerifyReply;
|
|
60
|
+
if (reply.success === true) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
console.warn(
|
|
64
|
+
`The ${adapter.kind} check refused a question:`,
|
|
65
|
+
reply["error-codes"] ?? response.status
|
|
66
|
+
);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(`The ${adapter.kind} check could not be reached:`, error);
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
};
|
package/src/cli/args.ts
CHANGED
|
@@ -21,3 +21,35 @@ export const parsePort = (value?: string): number | undefined => {
|
|
|
21
21
|
}
|
|
22
22
|
return port;
|
|
23
23
|
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The longest `--timeout` a timer can hold, in seconds. Node clamps a
|
|
27
|
+
* `setTimeout` delay above 2^31−1 ms (about 24.8 days) to 1 ms, so a larger
|
|
28
|
+
* value would time every agent out the moment it starts.
|
|
29
|
+
*/
|
|
30
|
+
export const MAX_TIMEOUT_S = Math.floor(2_147_483_647 / 1000);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parse a `--timeout` value in whole seconds, or return `fallback` when unset.
|
|
34
|
+
* A non-integer, non-positive, or too-long value exits with an error.
|
|
35
|
+
*/
|
|
36
|
+
export const parseTimeoutSeconds = (
|
|
37
|
+
value: string | undefined,
|
|
38
|
+
fallback: number
|
|
39
|
+
): number => {
|
|
40
|
+
if (value === undefined) {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
const timeout = Number(value);
|
|
44
|
+
if (!Number.isInteger(timeout) || timeout <= 0) {
|
|
45
|
+
logger.error(`Invalid --timeout "${value}" (whole seconds).`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
if (timeout > MAX_TIMEOUT_S) {
|
|
49
|
+
logger.error(
|
|
50
|
+
`Invalid --timeout "${value}" (at most ${MAX_TIMEOUT_S} seconds, about 24 days).`
|
|
51
|
+
);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
return timeout;
|
|
55
|
+
};
|
package/src/cli/command-meta.ts
CHANGED
|
@@ -62,6 +62,11 @@ export const commandMeta = {
|
|
|
62
62
|
description: "Preview the last production build.",
|
|
63
63
|
name: "preview",
|
|
64
64
|
},
|
|
65
|
+
skill: {
|
|
66
|
+
description:
|
|
67
|
+
"Write the docs site's agent skill with a coding agent, in place of the generated one.",
|
|
68
|
+
name: "skill",
|
|
69
|
+
},
|
|
65
70
|
sync: {
|
|
66
71
|
description: "Re-fetch remote content sources and regenerate the runtime.",
|
|
67
72
|
name: "sync",
|
|
@@ -238,7 +238,10 @@ export const auditCommand = defineCommand({
|
|
|
238
238
|
process.stderr.write(formatReport(result, root, { verbose: args.verbose }));
|
|
239
239
|
|
|
240
240
|
if (shouldFail(result, gate)) {
|
|
241
|
-
process.exit
|
|
241
|
+
// Set the code and return rather than `process.exit`, which doesn't wait
|
|
242
|
+
// for a piped stderr: a long report was cut off after the first 64 KiB,
|
|
243
|
+
// in exactly the CI logs that need to show every finding.
|
|
244
|
+
process.exitCode = 1;
|
|
242
245
|
}
|
|
243
246
|
},
|
|
244
247
|
});
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { BlumeError } from "../../core/diagnostics.ts";
|
|
15
15
|
import { packageRoot } from "../../core/package-root.ts";
|
|
16
16
|
import { scanProject } from "../../core/project-graph.ts";
|
|
17
|
+
import type { ResolvedConfig } from "../../core/schema.ts";
|
|
17
18
|
import { serverFeatures } from "../../core/server-features.ts";
|
|
18
19
|
import type { Diagnostic } from "../../core/types.ts";
|
|
19
20
|
import { unregisteredSnapshotDiagnostics } from "../../core/version-cut.ts";
|
|
@@ -71,6 +72,25 @@ const supportedNodeRange = (): string => {
|
|
|
71
72
|
}
|
|
72
73
|
};
|
|
73
74
|
|
|
75
|
+
/** The adapters a project runs, one line per kind, for the doctor summary. */
|
|
76
|
+
const integrationSummary = (config: ResolvedConfig): string[] => {
|
|
77
|
+
const { assistant } = config.ai;
|
|
78
|
+
let assistantSummary = "off";
|
|
79
|
+
if (assistant?.enabled) {
|
|
80
|
+
assistantSummary = assistant.endpoint
|
|
81
|
+
? "external endpoint"
|
|
82
|
+
: assistant.provider.kind;
|
|
83
|
+
}
|
|
84
|
+
return [
|
|
85
|
+
`References: ${config.reference.map((adapter) => adapter.kind).join(", ") || "none"}`,
|
|
86
|
+
`Analytics: ${config.analytics.map((adapter) => adapter.kind).join(", ") || "none"}`,
|
|
87
|
+
`Consent: ${config.consent?.kind ?? "none"}`,
|
|
88
|
+
`Rate limiting: ${config.rateLimit?.kind ?? "off"}`,
|
|
89
|
+
`Sources: ${config.content.sources.map((source) => source.kind).join(", ")}`,
|
|
90
|
+
`Assistant: ${assistantSummary}`,
|
|
91
|
+
];
|
|
92
|
+
};
|
|
93
|
+
|
|
74
94
|
export const doctorCommand = defineCommand({
|
|
75
95
|
args: {
|
|
76
96
|
json: {
|
|
@@ -144,23 +164,9 @@ export const doctorCommand = defineCommand({
|
|
|
144
164
|
logger.info(`Output: ${config.deployment.options.output}`);
|
|
145
165
|
logger.info(`Adapter: ${config.deployment.kind}`);
|
|
146
166
|
logger.info(`Search: ${config.search.provider.kind}`);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
);
|
|
150
|
-
logger.info(
|
|
151
|
-
`Analytics: ${config.analytics.map((adapter) => adapter.kind).join(", ") || "none"}`
|
|
152
|
-
);
|
|
153
|
-
logger.info(
|
|
154
|
-
`Sources: ${config.content.sources.map((source) => source.kind).join(", ")}`
|
|
155
|
-
);
|
|
156
|
-
const { assistant } = config.ai;
|
|
157
|
-
let assistantSummary = "off";
|
|
158
|
-
if (assistant?.enabled) {
|
|
159
|
-
assistantSummary = assistant.endpoint
|
|
160
|
-
? "external endpoint"
|
|
161
|
-
: assistant.provider.kind;
|
|
167
|
+
for (const line of integrationSummary(config)) {
|
|
168
|
+
logger.info(line);
|
|
162
169
|
}
|
|
163
|
-
logger.info(`Assistant: ${assistantSummary}`);
|
|
164
170
|
}
|
|
165
171
|
} catch (error) {
|
|
166
172
|
if (error instanceof BlumeError) {
|
|
@@ -187,7 +193,9 @@ export const doctorCommand = defineCommand({
|
|
|
187
193
|
logger.success("No problems found.");
|
|
188
194
|
}
|
|
189
195
|
if (hadErrors) {
|
|
190
|
-
process.exit
|
|
196
|
+
// Set the code and return rather than `process.exit`, which doesn't wait
|
|
197
|
+
// for a piped stderr: a long diagnostic list would be cut off.
|
|
198
|
+
process.exitCode = 1;
|
|
191
199
|
}
|
|
192
200
|
},
|
|
193
201
|
});
|
package/src/cli/commands/eval.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
|
-
import {
|
|
4
|
+
import { resolve } from "pathe";
|
|
5
5
|
|
|
6
6
|
import { AGENTS, launchAgent } from "../../audit/agent.ts";
|
|
7
7
|
import type { AgentKind } from "../../audit/agent.ts";
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { passFraction, runEval } from "../../eval/run.ts";
|
|
23
23
|
import type { EvalResult } from "../../eval/run.ts";
|
|
24
24
|
import { EvalsFileError, loadEvalsFile } from "../../eval/schema.ts";
|
|
25
|
+
import { parseTimeoutSeconds } from "../args.ts";
|
|
25
26
|
import { commandMeta } from "../command-meta.ts";
|
|
26
27
|
import { reportInternalError } from "../internal-error.ts";
|
|
27
28
|
import { flushStdout, logger, reportDiagnostics } from "../log.ts";
|
|
@@ -88,16 +89,18 @@ const parseFlags = (args: EvalFlags) => {
|
|
|
88
89
|
process.exit(1);
|
|
89
90
|
}
|
|
90
91
|
const threshold = args.threshold === undefined ? 1 : Number(args.threshold);
|
|
91
|
-
|
|
92
|
+
// A bare `--threshold` (or `--threshold $UNSET_VAR`) arrives as "", which
|
|
93
|
+
// `Number` reads as 0 — a gate that passes every run — so it's rejected.
|
|
94
|
+
if (
|
|
95
|
+
args.threshold?.trim() === "" ||
|
|
96
|
+
!Number.isFinite(threshold) ||
|
|
97
|
+
threshold < 0 ||
|
|
98
|
+
threshold > 1
|
|
99
|
+
) {
|
|
92
100
|
logger.error(`Invalid --threshold "${args.threshold}" (use 0..1).`);
|
|
93
101
|
process.exit(1);
|
|
94
102
|
}
|
|
95
|
-
const timeoutS =
|
|
96
|
-
args.timeout === undefined ? DEFAULT_TIMEOUT_S : Number(args.timeout);
|
|
97
|
-
if (!Number.isInteger(timeoutS) || timeoutS <= 0) {
|
|
98
|
-
logger.error(`Invalid --timeout "${args.timeout}" (whole seconds).`);
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
103
|
+
const timeoutS = parseTimeoutSeconds(args.timeout, DEFAULT_TIMEOUT_S);
|
|
101
104
|
return { agent: args.agent, threshold, timeoutS };
|
|
102
105
|
};
|
|
103
106
|
|
|
@@ -125,7 +128,7 @@ const runFixHandoff = async (
|
|
|
125
128
|
|
|
126
129
|
/** `blume eval init`: draft a starter evals file via the interactive agent. */
|
|
127
130
|
const runInit = async (agent: AgentKind, file: string): Promise<void> => {
|
|
128
|
-
const path =
|
|
131
|
+
const path = resolve(process.cwd(), file);
|
|
129
132
|
if (existsSync(path)) {
|
|
130
133
|
logger.error(
|
|
131
134
|
`${file} already exists — edit it directly, or pass --file to draft elsewhere.`
|
|
@@ -193,7 +196,9 @@ export const evalCommand = defineCommand({
|
|
|
193
196
|
// and never regenerates the runtime, so it doesn't contend with a
|
|
194
197
|
// running dev server. Same reasoning as `blume audit`.
|
|
195
198
|
const project = await scanProject(root, { mode: "build" });
|
|
196
|
-
|
|
199
|
+
// `resolve`, not `join`: an absolute `--file` (`/ci/evals.yaml`) is
|
|
200
|
+
// used as given instead of being nested under the project root.
|
|
201
|
+
const evalsPath = resolve(root, args.file);
|
|
197
202
|
const { evals, raw } = await loadEvalsFile(evalsPath);
|
|
198
203
|
|
|
199
204
|
process.stderr.write(`${headerLine(evals.questions.length, agent)}\n\n`);
|
|
@@ -270,7 +275,10 @@ export const evalCommand = defineCommand({
|
|
|
270
275
|
}
|
|
271
276
|
|
|
272
277
|
if (failed) {
|
|
273
|
-
process.exit
|
|
278
|
+
// Set the code and return rather than `process.exit`, which doesn't wait
|
|
279
|
+
// for a piped stderr: a long `--verbose` report was cut off mid-write, in
|
|
280
|
+
// exactly the CI logs that need to show every failure.
|
|
281
|
+
process.exitCode = 1;
|
|
274
282
|
}
|
|
275
283
|
},
|
|
276
284
|
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
import { join } from "pathe";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
planSkill,
|
|
6
|
+
WRITE_SKILL_DIR,
|
|
7
|
+
writeSkillPrompt,
|
|
8
|
+
} from "../../ai/write-skill.ts";
|
|
9
|
+
import { AGENTS, launchInstalledAgent } from "../../audit/agent.ts";
|
|
10
|
+
import type { AgentKind } from "../../audit/agent.ts";
|
|
11
|
+
import { BlumeError } from "../../core/diagnostics.ts";
|
|
12
|
+
import { packageRoot } from "../../core/package-root.ts";
|
|
13
|
+
import { scanProject } from "../../core/project-graph.ts";
|
|
14
|
+
import { getBlumeVersion } from "../../core/version.ts";
|
|
15
|
+
import { commandMeta } from "../command-meta.ts";
|
|
16
|
+
import { reportInternalError } from "../internal-error.ts";
|
|
17
|
+
import { logger, reportDiagnostics } from "../log.ts";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* `blume skill` — write the docs site's agent skill with a coding agent. Every
|
|
21
|
+
* build publishes a generated skill at `/skill.md` (a map of the docs); this
|
|
22
|
+
* opens Claude Code or Codex on the `blume-write-skill` skill bundled in this
|
|
23
|
+
* package to write the richer one, grounded in the docs, under the same name
|
|
24
|
+
* so it takes the generated one's place. The judgment stays in the skill; the
|
|
25
|
+
* command is the front door, like `blume migrate`. Status lines go straight to
|
|
26
|
+
* stderr: consola drops info-level lines in test and CI environments.
|
|
27
|
+
*/
|
|
28
|
+
export const skillCommand = defineCommand({
|
|
29
|
+
args: {
|
|
30
|
+
claude: {
|
|
31
|
+
description: "Write the skill with Claude Code.",
|
|
32
|
+
type: "boolean",
|
|
33
|
+
},
|
|
34
|
+
codex: {
|
|
35
|
+
description: "Write the skill with Codex.",
|
|
36
|
+
type: "boolean",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
meta: commandMeta.skill,
|
|
40
|
+
async run({ args }) {
|
|
41
|
+
const root = process.cwd();
|
|
42
|
+
// SAFETY: AGENTS is a closed record keyed by AgentKind, so its keys are
|
|
43
|
+
// exactly the agent kinds.
|
|
44
|
+
const agents = (Object.keys(AGENTS) as AgentKind[]).filter(
|
|
45
|
+
(kind) => args[kind]
|
|
46
|
+
);
|
|
47
|
+
if (agents.length > 1) {
|
|
48
|
+
logger.error("Pass at most one of --codex or --claude.");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
const [agent] = agents;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// A scan, not `prepareProject`: the agent reads the content tree and
|
|
55
|
+
// the runtime isn't touched, so a running dev server is left alone.
|
|
56
|
+
const plan = planSkill(await scanProject(root, { mode: "build" }));
|
|
57
|
+
const skillDir = join(packageRoot(), WRITE_SKILL_DIR);
|
|
58
|
+
process.stderr.write(
|
|
59
|
+
` ${plan.exists ? "Updating" : "Writing"} the "${plan.name}" skill at ${plan.file}.\n`
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Without an agent flag the command is the pointer for any other agent:
|
|
63
|
+
// the bundled skill's path, and the install line that puts the skill
|
|
64
|
+
// where agents look for it.
|
|
65
|
+
if (!agent) {
|
|
66
|
+
process.stderr.write(
|
|
67
|
+
` blume skill writes it with a coding agent: rerun with --codex or --claude.\n Using another agent? Point it at ${join(skillDir, "SKILL.md")},\n or install the skill where your agent looks for skills: npx skills add haydenbleasel/blume --skill blume-write-skill\n`
|
|
68
|
+
);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const cli = AGENTS[agent];
|
|
73
|
+
process.stderr.write(` Handing it to ${cli.name}…\n\n`);
|
|
74
|
+
const code = await launchInstalledAgent(
|
|
75
|
+
cli.bin,
|
|
76
|
+
writeSkillPrompt(plan, { skillDir, version: getBlumeVersion() })
|
|
77
|
+
);
|
|
78
|
+
if (code === null) {
|
|
79
|
+
logger.error(
|
|
80
|
+
`${cli.name} (\`${cli.bin}\`) was not found on PATH. Install it with \`${cli.install}\`.`
|
|
81
|
+
);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
if (code !== 0) {
|
|
85
|
+
process.exit(code);
|
|
86
|
+
}
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (error instanceof BlumeError) {
|
|
89
|
+
reportDiagnostics([error.diagnostic], root);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
reportInternalError(error);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
});
|