diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 0000000..f25f38a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1,11 @@ +blank_issues_enabled: true +contact_links: + - name: "\U0001F4AC Discord Chat" + url: https://bomb.sh/chat + about: Our Discord server is active, come join us for support and chat! + - name: "\U0001F98B Bluesky" + url: https://bsky.app/profile/bomb.sh + about: Follow us on Bluesky for updates, news, and announcements. + - name: "\U0001F496 Sponsor" + url: https://opencollective.com/bombshell-dev + about: Support the development of bombshell projects via Open Collective! diff --git a/.github/ISSUE_TEMPLATE/docs_issue.yaml b/.github/ISSUE_TEMPLATE/docs_issue.yaml new file mode 100644 index 0000000..e2ccd71 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs_issue.yaml @@ -0,0 +1,49 @@ +name: "\U0001F4DA Documentation improvement" +description: Report a typo, outdated info, or suggest new documentation +labels: ["documentation"] +body: + - type: markdown + attributes: + value: | + Thanks for helping us improve our documentation! Clear docs make the whole bombshell ecosystem better for everyone. + - type: dropdown + id: package + attributes: + label: Related Package + description: Which package's documentation needs improvement? + options: + - "@clack/core" + - "@clack/prompts" + - "@bomb.sh/tab" + - "@bomb.sh/args" + - "General / Website Docs" + validations: + required: true + - type: textarea + id: current-issue + attributes: + label: What needs to be changed? + description: Describe the typo, outdated section, or missing concept. Please include links to the current documentation if applicable. + validations: + required: true + - type: textarea + id: proposed-change + attributes: + label: Proposed improvement / suggestion + description: A clear description of what should be written or fixed. Feel free to provide a rough draft or code snippets of the expected output! + validations: + required: true + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Add any other context or screenshots that might help explain your suggestion. + validations: + required: false + - type: checkboxes + id: ai-disclosure + attributes: + label: AI assistance disclosure + options: + - label: This report was drafted with the assistance of an AI tool. + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..6c2bf9b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,23 @@ +## What does this PR do? + + + +Closes # + +## Type of change + + + +- [ ] Typo +- [ ] New Documentation for Feature +- [ ] Improvement for Clarification +- [ ] Chore (dependencies, CI, tooling) + +## AI-generated code disclosure + + + +- [ ] This PR includes AI-generated code diff --git a/.gitignore b/.gitignore index ceb713d..adf1a8e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ dist/ # generated types .astro/ public/snapshot +public/llms.txt +public/docs-index.json # dependencies node_modules/ diff --git a/astro.config.mjs b/astro.config.mjs index 4ad7ceb..c4f0589 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,9 +1,18 @@ -import starlight from "@astrojs/starlight"; // @ts-check import { defineConfig } from "astro/config"; - +import starlight from "@astrojs/starlight"; import ecTwoSlash from "expressive-code-twoslash"; import topics from "starlight-sidebar-topics"; +import starlightMarkdown from "starlight-markdown"; +import mermaid from "astro-mermaid"; +import { fileURLToPath } from "node:url"; +import { ecThemes } from "./src/ec-themes.mjs"; + +/** Pick a value per code theme; keeps styleOverrides below readable. */ +const byTheme = (dark, light) => ({ theme }) => + theme.type === "dark" ? dark : light; + +const docsRoot = fileURLToPath(new URL(".", import.meta.url)); const site = "https://bomb.sh/docs/"; @@ -21,6 +30,7 @@ export default defineConfig({ } }, integrations: [ + mermaid({ autoTheme: true }), starlight({ title: "Bombshell", logo: { @@ -28,19 +38,76 @@ export default defineConfig({ light: "./src/assets/light.svg", }, customCss: [ - './src/styles/tint.css' + './src/styles/tint.css', + './src/styles/asides.css' ], components: { Head: "./src/starlightOverrides/Head.astro", + Header: "./src/starlightOverrides/Header.astro", + SiteTitle: "./src/starlightOverrides/SiteTitle.astro", + Footer: "./src/starlightOverrides/Footer.astro", + MarkdownContent: "./src/starlightOverrides/MarkdownContent.astro", + MobileMenuFooter: "./src/starlightOverrides/MobileMenuFooter.astro", }, expressiveCode: { - themes: ['github-dark-high-contrast', 'github-light-high-contrast'], + themes: ecThemes, styleOverrides: { + codeFontFamily: '"dm-mono", ui-monospace, monospace', + uiFontFamily: '"dm-mono", ui-monospace, monospace', + borderRadius: "4px", + borderWidth: "1px", + borderColor: byTheme("#2b2e38", "#c4c7cf"), + codeBackground: byTheme("#000000", "#ffffff"), + frames: { + shadowColor: "transparent", + frameBoxShadowCssValue: "none", + terminalBackground: byTheme("#000000", "#ffffff"), + terminalTitlebarBackground: "transparent", + terminalTitlebarBorderBottomColor: "transparent", + terminalTitlebarForeground: byTheme("#8a8e9b", "#6c6e79"), + terminalTitlebarDotsForeground: byTheme("#484a54", "#c4c7cf"), + editorTabBarBackground: "transparent", + editorTabBarBorderColor: "transparent", + editorTabBarBorderBottomColor: "transparent", + editorActiveTabBackground: "transparent", + editorActiveTabForeground: byTheme("#f4f5f9", "#0a0a0d"), + editorActiveTabBorderColor: "transparent", + editorActiveTabIndicatorTopColor: byTheme("#ff00d2", "#b8009c"), + editorActiveTabIndicatorBottomColor: "transparent", + }, twoSlash: { - cursorColor: 'rgba(255 0 210)' - } + cursorColor: "#ff00d2", + borderColor: byTheme("#2b2e38", "#c4c7cf"), + background: byTheme("#191b23", "#ffffff"), + textColor: byTheme("#f4f5f9", "#0a0a0d"), + hoverUnderlineColor: byTheme("#8a8e9b", "#a9abb6"), + tagColor: byTheme("#00e5ff", "#00798a"), + linkColor: byTheme("#00e5ff", "#00798a"), + linkColorHover: byTheme("#ffffff", "#0a0a0d"), + errorColor: byTheme("#ff3e47", "#d21f28"), + warnColor: byTheme("#e8cf27", "#a37e00"), + suggestionColor: byTheme("#07f53f", "#00842e"), + messageColor: byTheme("#c4c7cf", "#484a54"), + completionBoxBackground: byTheme("#191b23", "#ffffff"), + completionBoxBorder: byTheme("#2b2e38", "#c4c7cf"), + completionBoxColor: byTheme("#f4f5f9", "#0a0a0d"), + completionBoxMatchedColor: byTheme("#00e5ff", "#00798a"), + completionBoxHoverBackground: byTheme("#2b2e38", "#f4f5f9"), + highlightHue: "311", + }, }, - plugins: [ecTwoSlash()], + plugins: [ecTwoSlash({ + twoslashOptions: { + compilerOptions: { + module: 99, + moduleResolution: 100, + baseUrl: docsRoot, + paths: { + "@bomb.sh/tty": ["node_modules/@bomb.sh/tty/esm/mod.d.ts"], + }, + }, + }, + })], }, editLink: { baseUrl: "https://github.com/bombshell-dev/docs/edit/main/", @@ -50,7 +117,7 @@ export default defineConfig({ tag: "link", attrs: { rel: "stylesheet", - href: "https://use.typekit.net/bst3mzh.css?v=5", + href: "https://use.typekit.net/bst3mzh.css?v=7", }, }, { @@ -88,6 +155,7 @@ export default defineConfig({ { icon: 'github', label: 'GitHub', href: 'https://bomb.sh/on/github' }, ], plugins: [ + starlightMarkdown(), topics([ { label: "Clack", @@ -123,6 +191,27 @@ export default defineConfig({ link: "/tab/", items: [], }, + { + label: "TTY", + id: "tty", + icon: "seti:config", + link: "/tty/basics/getting-started", + items: [ + { label: "Basics", autogenerate: { directory: "tty/basics" } }, + { label: "Guides", autogenerate: { directory: "tty/guides" } }, + { + label: "API", + items: [ + { label: "Overview", link: "/tty/api/" }, + { label: "Ops", link: "/tty/api/ops" }, + { label: "Term", link: "/tty/api/term" }, + { label: "Input", link: "/tty/api/input" }, + { label: "Settings", link: "/tty/api/settings" }, + { label: "Termcodes", link: "/tty/api/termcodes" }, + ], + }, + ], + }, ]), ], }), diff --git a/package.json b/package.json index 60d475e..e3c0421 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,21 @@ "scripts": { "dev": "astro dev", "start": "astro dev", - "prebuild": "npm run snapshot", + "prebuild": "pnpm run snapshot && pnpm run generate:docs-index", + "predev": "pnpm run generate:docs-index", "build": "astro build && cp public/_headers dist/_headers", "preview": "astro preview", "astro": "astro", - "snapshot": "node --experimental-strip-types ./scripts/snapshot.ts" + "snapshot": "node --experimental-strip-types ./scripts/snapshot.ts", + "generate:docs-index": "node --experimental-strip-types ./scripts/generate-docs-index.ts" }, "dependencies": { "@astrojs/starlight": "^0.37.1", "@bomb.sh/args": "^0.3.1", - "@clack/core": "^1.4.0", - "@clack/prompts": "^1.5.0", + "@bomb.sh/tty": "^0.8.0", + "@clack/core": "^1.4.3", + "@clack/prompts": "^1.7.0", + "@fontsource-variable/inter": "^5.3.0", "@types/node": "^22.19.3", "@webcontainer/api": "^1.6.1", "@webcontainer/snapshot": "^0.1.0", @@ -24,13 +28,17 @@ "@xterm/xterm": "^6.0.0", "arktype": "^2.2.0", "astro": "^5.16.6", + "astro-mermaid": "^2.1.0", "expressive-code-twoslash": "^0.5.3", + "mermaid": "^11.16.0", "sharp": "^0.33.5", + "starlight-markdown": "^0.1.5", "starlight-sidebar-topics": "^0.6.2" }, "devDependencies": { + "astro-vtbot": "^3.1.0", "tinyexec": "^1.0.2", - "wrangler": "^4.14.4" + "wrangler": "^4.97.0" }, "packageManager": "pnpm@11.1.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c074aa..21304b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,12 +14,18 @@ importers: '@bomb.sh/args': specifier: ^0.3.1 version: 0.3.1 + '@bomb.sh/tty': + specifier: ^0.8.0 + version: 0.8.0 '@clack/core': - specifier: ^1.4.0 - version: 1.4.0 + specifier: ^1.4.3 + version: 1.4.3 '@clack/prompts': - specifier: ^1.5.0 - version: 1.5.0 + specifier: ^1.7.0 + version: 1.7.0 + '@fontsource-variable/inter': + specifier: ^5.3.0 + version: 5.3.0 '@types/node': specifier: ^22.19.3 version: 22.19.3 @@ -44,22 +50,34 @@ importers: astro: specifier: ^5.16.6 version: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2) + astro-mermaid: + specifier: ^2.1.0 + version: 2.1.0(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2))(mermaid@11.16.0) expressive-code-twoslash: specifier: ^0.5.3 version: 0.5.3(@expressive-code/core@0.41.5)(expressive-code@0.41.5)(typescript@5.8.2) + mermaid: + specifier: ^11.16.0 + version: 11.16.0 sharp: specifier: ^0.33.5 version: 0.33.5 + starlight-markdown: + specifier: ^0.1.5 + version: 0.1.5(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2)) starlight-sidebar-topics: specifier: ^0.6.2 version: 0.6.2(@astrojs/starlight@0.37.1(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2))) devDependencies: + astro-vtbot: + specifier: ^3.1.0 + version: 3.1.0 tinyexec: specifier: ^1.0.2 version: 1.0.2 wrangler: - specifier: ^4.14.4 - version: 4.80.0(@cloudflare/workers-types@4.20260405.1) + specifier: ^4.97.0 + version: 4.97.0 router: devDependencies: @@ -72,6 +90,9 @@ importers: packages: + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@ark/schema@0.56.0': resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} @@ -133,22 +154,36 @@ packages: '@bomb.sh/args@0.3.1': resolution: {integrity: sha512-CwxKrfgcorUPP6KfYD59aRdBYWBTsfsxT+GmoLVnKo5Tmyoqbpo0UNcjngRMyU+6tiPbd18RuIYxhgAn44wU/Q==} + '@bomb.sh/tty@0.8.0': + resolution: {integrity: sha512-tEE0mtqnEp2uJt4kQS5AjdghCD5KN4BobqHOlfhaiNyrigxFBKk61XkDy//4D7V/AejrTvubh44B4NV35lsnxw==} + engines: {node: '>= 22'} + + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + '@capsizecss/unpack@3.0.1': resolution: {integrity: sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg==} engines: {node: '>=18'} - '@clack/core@1.4.0': - resolution: {integrity: sha512-7Wctjq6f7c1CPz8sPpkwUnz8yRgVANkpNupb81q432FjcJg4l+Sw7XANdNSdWfAKq0IHI0JTcUeK5dxs/HrGPw==} + '@chevrotain/types@11.1.2': + resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} + + '@clack/core@1.4.3': + resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} engines: {node: '>= 20.12.0'} - '@clack/prompts@1.5.0': - resolution: {integrity: sha512-wKh+wTjmrUoUdkZg8KpJO5X+p9PWV+KE9mePseq9UYWkukgTKsGS47RRL2HstwVcvDQH+PenrPJWII8+MfiiyA==} + '@clack/prompts@1.7.0': + resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==} engines: {node: '>= 20.12.0'} '@cloudflare/kv-asset-handler@0.4.2': resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} engines: {node: '>=18.0.0'} + '@cloudflare/kv-asset-handler@0.5.0': + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} + engines: {node: '>=22.0.0'} + '@cloudflare/unenv-preset@2.16.0': resolution: {integrity: sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg==} peerDependencies: @@ -158,36 +193,75 @@ packages: workerd: optional: true + '@cloudflare/unenv-preset@2.16.1': + resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: '>1.20260305.0 <2.0.0-0' + peerDependenciesMeta: + workerd: + optional: true + '@cloudflare/workerd-darwin-64@1.20260401.1': resolution: {integrity: sha512-ZSmceM70jH6k+/62VkEcmMNzrpr4kSctkX5Lsgqv38KktfhPY/hsh75y1lRoPWS3H3kgMa4p2pUSlidZR1u2hw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] + '@cloudflare/workerd-darwin-64@1.20260601.1': + resolution: {integrity: sha512-iXZBVuRbvuVqQ/63wul01hHCv/3R8G5S8zbkjfoHvyPZFynmlKTV59Hk+H8whyGwFAZuB71UJGLr+G5mJKfjWA==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20260401.1': resolution: {integrity: sha512-7UKWF+IUZ3NXMVPsDg8Cjg0r58b+uYlfvs5Yt8bvtU+geCtW4P2MxRHmRSEo8SryckXOJjb/b8tcncgCykFu8g==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20260601.1': + resolution: {integrity: sha512-veGpZQGBw07Twt+Y4z3oyo+/obKHt0iWUwvDV5GOiDAYjC/zW+YGstgVzg4SHq+k1sLH3ElqL2TXx20I5WBv3Q==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + '@cloudflare/workerd-linux-64@1.20260401.1': resolution: {integrity: sha512-MDWUH/0bvL/l9aauN8zEddyYOXId1OueqrUCXXENNJ95R/lSmF6OgGVuXaYhoIhxQkNiEJ/0NOlnVYj9mJq4dw==} engines: {node: '>=16'} cpu: [x64] os: [linux] + '@cloudflare/workerd-linux-64@1.20260601.1': + resolution: {integrity: sha512-n/9hDz7fPGpYF0J684+Xr5zgjcS2jdmY2Of5m6e+eQ/M9+RfR+UaU8Ee/tkA1dDC0LYQB13hfPafZG66Ff1CsA==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + '@cloudflare/workerd-linux-arm64@1.20260401.1': resolution: {integrity: sha512-UgkzpMzVWM/bwbo3vjCTg2aoKfGcUhiEoQoDdo6RGWvbHRJyLVZ4VQCG9ZcISiztkiS2ICCoYOtPy6M/lV6Gcw==} engines: {node: '>=16'} cpu: [arm64] os: [linux] + '@cloudflare/workerd-linux-arm64@1.20260601.1': + resolution: {integrity: sha512-VHRZZbexATS+n+1j3x/CZaYbIJEye0J3iIHgG0Wp+l+NrZCKQ8qi8Lq1uTV0dLJQ67FuZtJtWdQ95mm9F7Fc+A==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + '@cloudflare/workerd-windows-64@1.20260401.1': resolution: {integrity: sha512-HBLzcQF5iF4Qv20tQ++pG7xs3OsCnaIbc+GAi6fmhUKZhvmzvml/jwrQzLJ+MPm0cQo41K5OO/U3T4S8tvJetQ==} engines: {node: '>=16'} cpu: [x64] os: [win32] + '@cloudflare/workerd-windows-64@1.20260601.1': + resolution: {integrity: sha512-ye0C7MFLkeH16iTo8Tcjv2KiFmp23+sZGvUzSQa4xhP0QMe6EoJ+H/4SqqvnZ5nfN54slqKvx2VnXceENWe2CQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + '@cloudflare/workers-types@4.20260405.1': resolution: {integrity: sha512-PokTmySa+D6MY01R1UfYH48korsN462NK/fl3aw47Hg7XuLuSo/RTpjT0vtWaJhJoFY5tHGOBBIbDcIc8wltLg==} @@ -526,6 +600,15 @@ packages: '@expressive-code/plugin-text-markers@0.41.5': resolution: {integrity: sha512-0DSiTsjWFEz6/iuLOGNNy2GaeCW41OwnVJMKx1tS+XKeQxAL89UkZP3egWNzxjWNHNMzEv3ZWWWYqbonEQlv/Q==} + '@fontsource-variable/inter@5.3.0': + resolution: {integrity: sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.4': + resolution: {integrity: sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==} + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -809,6 +892,9 @@ packages: '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + '@mermaid-js/parser@1.2.0': + resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@msgpack/msgpack@3.1.3': resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==} engines: {node: '>= 18'} @@ -1036,6 +1122,99 @@ packages: '@swc/helpers@0.5.18': resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.4': + resolution: {integrity: sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -1048,6 +1227,9 @@ packages: '@types/fontkit@2.0.8': resolution: {integrity: sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -1075,6 +1257,9 @@ packages: '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1088,6 +1273,25 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher + + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + + '@vtbag/cam-shaft@1.0.6': + resolution: {integrity: sha512-Xy1bmJJLXuCqxmY2agwPfhGNv1XZViqh54H0VGK4mouGsItFsh8Mz/wWAP6mZwAOEuu9bEOJ1mJ+oNoaczZ1zw==} + + '@vtbag/element-crossing@1.1.0': + resolution: {integrity: sha512-1YL609KPwhHUKRrVNfoogQCVJPfFrE5DubOLcCJZLHVCjWZ2ZAPcaq1wR2OP6nXD0Ok9JLX41YsEtYBYzw6CxQ==} + + '@vtbag/inspection-chamber@1.0.24': + resolution: {integrity: sha512-L6CrMbzJ0gdG/P5WnGyVgRxHVeLhlQgXh3mp+OI4JdJjFiwIhh9+sG/FXM2DneBs5HQvaWUq4qf6NiSlgVbyvQ==} + + '@vtbag/turn-signal@1.3.1': + resolution: {integrity: sha512-6rWkG+ik3U+KQGI94yNOrOh5QedB9zmP/8H51X5WQwrJz8m2MAU5YwGRRcweO/dJ6wW/Bn7OsgC1vRURnwrvCg==} + + '@vtbag/utensil-drawer@1.2.18': + resolution: {integrity: sha512-Veg1J8lviA2g878otiEHoyiGR2f4PZ5Rc40UyIR4YS95QnD+1+oAZsprhUPR+YudgZPrqWx5chyPNwjkHyA0uw==} '@webcontainer/api@1.6.1': resolution: {integrity: sha512-2RS2KiIw32BY1Icf6M1DvqSmcon9XICZCDgS29QJb2NmF12ZY2V5Ia+949hMKB3Wno+P/Y8W+sPP59PZeXSELg==} @@ -1162,6 +1366,19 @@ packages: peerDependencies: astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 + astro-mermaid@2.1.0: + resolution: {integrity: sha512-fFRUN0BTZh+DZhDiLyblXoO26XqJ1Rr+qK3JGgSu7OBspKHDm59jkztg/aHsrdo1vO/tIq/+xhP/vgT8Mp92XA==} + peerDependencies: + '@mermaid-js/layout-elk': ^0.2.0 + astro: '>=4' + mermaid: ^10.0.0 || ^11.0.0 + peerDependenciesMeta: + '@mermaid-js/layout-elk': + optional: true + + astro-vtbot@3.1.0: + resolution: {integrity: sha512-YZX+Sv3EHRaAryyEJ28N9ausnAG4JxM9ivY+BeRJEa/neWBHmZaQ3onMcdxBFg/u7e+8+YOepuQC8Bt2lx8fKg==} + astro@5.16.6: resolution: {integrity: sha512-6mF/YrvwwRxLTu+aMEa5pwzKUNl5ZetWbTyZCs9Um0F12HUmxUiF5UHiZPy4rifzU3gtpM3xP2DfdmkNX9eZRg==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} @@ -1266,6 +1483,14 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} @@ -1276,6 +1501,12 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + crossws@0.3.5: resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} @@ -1306,6 +1537,165 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.34.0: + resolution: {integrity: sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1321,6 +1711,9 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1366,6 +1759,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.4.11: + resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -1393,6 +1789,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-toolkit@1.49.0: + resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==} + esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -1499,6 +1898,9 @@ packages: h3@1.15.4: resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + hast-util-embedded@3.0.0: resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} @@ -1574,12 +1976,23 @@ packages: i18next@23.16.8: resolution: {integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + import-meta-resolve@4.2.0: resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -1624,6 +2037,13 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + katex@0.16.47: + resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -1636,6 +2056,15 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -1655,6 +2084,11 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} @@ -1715,6 +2149,9 @@ packages: mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mermaid@11.16.0: + resolution: {integrity: sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -1828,6 +2265,11 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + miniflare@4.20260601.0: + resolution: {integrity: sha512-56TFiulSEQu43cYxdXgCiA3U3i+Ls0NoXwJXd6DmpNsx8yl/1Il2T3DQ4CMXjR6yfE7CSvC5MuXaqcSAMREjgw==} + engines: {node: '>=22.0.0'} + hasBin: true + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -1903,6 +2345,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} @@ -1923,6 +2368,16 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss-nested@6.2.0: resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} engines: {node: '>=12.0'} @@ -2036,11 +2491,23 @@ packages: retext@9.0.0: resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rollup@4.55.1: resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.3: resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} @@ -2086,6 +2553,11 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + starlight-markdown@0.1.5: + resolution: {integrity: sha512-23LXRaZp7pyE+r/HP6rxHfwic8HfvUBT4EImECA6encs/eTtrF0Z+7svANofdtfbiNt31D5q26i03B6FtcSmGg==} + peerDependencies: + astro: ^5.0.0 + starlight-sidebar-topics@0.6.2: resolution: {integrity: sha512-SNCTUZS/hcVor0ZcaXbaSVU37+V+qtvzNirkvnOg3Mqu/awuGpthkH5+uKpiZqWxLffp6TrOlsv5E5QsxrndNg==} engines: {node: '>=18'} @@ -2120,6 +2592,9 @@ packages: style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} + supports-color@10.2.2: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} @@ -2146,9 +2621,14 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-dedent@2.3.0: + resolution: {integrity: sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==} + engines: {node: '>=6.10'} + tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} + deprecated: unmaintained hasBin: true peerDependencies: typescript: ^5.0.0 @@ -2192,6 +2672,10 @@ packages: resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==} engines: {node: '>=20.18.1'} + undici@7.24.8: + resolution: {integrity: sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==} + engines: {node: '>=20.18.1'} + unenv@2.0.0-rc.24: resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} @@ -2302,6 +2786,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@14.0.1: + resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==} + hasBin: true + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -2375,6 +2863,11 @@ packages: engines: {node: '>=16'} hasBin: true + workerd@1.20260601.1: + resolution: {integrity: sha512-Bg4+HF3B8TW0urAv8chiz25HSQ/aJxMBjgheUzu/nB1NQa+CaKGrUPv+Z3bf0np/WxLHYW1kcseVEtzZVPbX4g==} + engines: {node: '>=16'} + hasBin: true + wrangler@4.80.0: resolution: {integrity: sha512-2ZKF7uPeOZy65BGk3YfvqBCPo/xH1MrAlMmH9mVP+tCNBrTUMnwOHSj1HrZHgR8LttkAqhko0fGz+I4ax1rzyQ==} engines: {node: '>=20.3.0'} @@ -2385,6 +2878,16 @@ packages: '@cloudflare/workers-types': optional: true + wrangler@4.97.0: + resolution: {integrity: sha512-jzW/aNvjerV+4TmwbvwGY6lpcuBk7EFUTonMDNfci45wSmMTj2/OJN+83cc/CeepKdb+6ZjGJw9NRjmcQoxqRg==} + engines: {node: '>=22.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20260601.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -2401,6 +2904,18 @@ packages: utf-8-validate: optional: true + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xxhash-wasm@1.1.0: resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} @@ -2445,6 +2960,11 @@ packages: snapshots: + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 + '@ark/schema@0.56.0': dependencies: '@ark/util': 0.56.0 @@ -2573,45 +3093,74 @@ snapshots: '@bomb.sh/args@0.3.1': {} + '@bomb.sh/tty@0.8.0': {} + + '@braintree/sanitize-url@7.1.2': {} + '@capsizecss/unpack@3.0.1': dependencies: fontkit: 2.0.4 - '@clack/core@1.4.0': + '@chevrotain/types@11.1.2': {} + + '@clack/core@1.4.3': dependencies: fast-wrap-ansi: 0.2.0 sisteransi: 1.0.5 - '@clack/prompts@1.5.0': + '@clack/prompts@1.7.0': dependencies: - '@clack/core': 1.4.0 + '@clack/core': 1.4.3 fast-string-width: 3.0.2 fast-wrap-ansi: 0.2.0 sisteransi: 1.0.5 '@cloudflare/kv-asset-handler@0.4.2': {} + '@cloudflare/kv-asset-handler@0.5.0': {} + '@cloudflare/unenv-preset@2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260401.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: workerd: 1.20260401.1 + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260601.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20260601.1 + '@cloudflare/workerd-darwin-64@1.20260401.1': optional: true + '@cloudflare/workerd-darwin-64@1.20260601.1': + optional: true + '@cloudflare/workerd-darwin-arm64@1.20260401.1': optional: true + '@cloudflare/workerd-darwin-arm64@1.20260601.1': + optional: true + '@cloudflare/workerd-linux-64@1.20260401.1': optional: true + '@cloudflare/workerd-linux-64@1.20260601.1': + optional: true + '@cloudflare/workerd-linux-arm64@1.20260401.1': optional: true + '@cloudflare/workerd-linux-arm64@1.20260601.1': + optional: true + '@cloudflare/workerd-windows-64@1.20260401.1': optional: true + '@cloudflare/workerd-windows-64@1.20260601.1': + optional: true + '@cloudflare/workers-types@4.20260405.1': {} '@cspotcode/source-map-support@0.8.1': @@ -2806,6 +3355,16 @@ snapshots: dependencies: '@expressive-code/core': 0.41.5 + '@fontsource-variable/inter@5.3.0': {} + + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.4': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + import-meta-resolve: 4.2.0 + '@img/colour@1.0.0': {} '@img/sharp-darwin-arm64@0.33.5': @@ -3016,6 +3575,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@mermaid-js/parser@1.2.0': + dependencies: + '@chevrotain/types': 11.1.2 + '@msgpack/msgpack@3.1.3': {} '@oslojs/encoding@1.1.0': {} @@ -3176,6 +3739,123 @@ snapshots: dependencies: tslib: 2.8.1 + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.4': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -3190,6 +3870,8 @@ snapshots: dependencies: '@types/node': 22.19.3 + '@types/geojson@7946.0.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -3218,6 +3900,9 @@ snapshots: dependencies: '@types/node': 22.19.3 + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -3231,6 +3916,21 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + '@vtbag/cam-shaft@1.0.6': {} + + '@vtbag/element-crossing@1.1.0': {} + + '@vtbag/inspection-chamber@1.0.24': {} + + '@vtbag/turn-signal@1.3.1': {} + + '@vtbag/utensil-drawer@1.2.18': {} + '@webcontainer/api@1.6.1': {} '@webcontainer/snapshot@0.1.0': @@ -3289,6 +3989,22 @@ snapshots: astro: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2) rehype-expressive-code: 0.41.5 + astro-mermaid@2.1.0(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2))(mermaid@11.16.0): + dependencies: + astro: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2) + import-meta-resolve: 4.2.0 + mdast-util-to-string: 4.0.0 + mermaid: 11.16.0 + unist-util-visit: 5.0.0 + + astro-vtbot@3.1.0: + dependencies: + '@vtbag/cam-shaft': 1.0.6 + '@vtbag/element-crossing': 1.1.0 + '@vtbag/inspection-chamber': 1.0.24 + '@vtbag/turn-signal': 1.3.1 + '@vtbag/utensil-drawer': 1.2.18 + astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2): dependencies: '@astrojs/compiler': 2.13.0 @@ -3474,12 +4190,24 @@ snapshots: commander@11.1.0: {} + commander@7.2.0: {} + + commander@8.3.0: {} + common-ancestor-path@1.0.1: {} cookie-es@1.2.2: {} cookie@1.1.1: {} + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + crossws@0.3.5: dependencies: uncrypto: 0.1.3 @@ -3512,6 +4240,192 @@ snapshots: dependencies: css-tree: 2.2.1 + cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.0): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.34.0 + + cytoscape-fcose@2.2.0(cytoscape@3.34.0): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.34.0 + + cytoscape@3.34.0: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.18.1 + + dayjs@1.11.21: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -3522,6 +4436,10 @@ snapshots: defu@6.1.4: {} + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 + dequal@2.0.3: {} destr@2.0.5: {} @@ -3558,6 +4476,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.4.11: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -3578,6 +4500,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-toolkit@1.49.0: {} + esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -3722,9 +4646,9 @@ snapshots: dependencies: fast-string-width: 3.0.2 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 flattie@1.1.1: {} @@ -3764,6 +4688,8 @@ snapshots: ufo: 1.6.1 uncrypto: 0.1.3 + hachure-fill@0.5.2: {} + hast-util-embedded@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -3965,10 +4891,18 @@ snapshots: dependencies: '@babel/runtime': 7.28.4 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + import-meta-resolve@4.2.0: {} inline-style-parser@0.2.7: {} + internmap@1.0.1: {} + + internmap@2.0.3: {} + iron-webcrypto@1.2.1: {} is-alphabetical@2.0.1: {} @@ -4002,12 +4936,24 @@ snapshots: dependencies: argparse: 2.0.1 + katex@0.16.47: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + kleur@3.0.3: {} kleur@4.1.5: {} klona@2.0.6: {} + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + + lodash-es@4.18.1: {} + longest-streak@3.1.0: {} lru-cache@10.4.3: {} @@ -4026,6 +4972,8 @@ snapshots: markdown-table@3.0.4: {} + marked@16.4.2: {} + mdast-util-definitions@6.0.0: dependencies: '@types/mdast': 4.0.4 @@ -4213,6 +5161,30 @@ snapshots: mdn-data@2.12.2: {} + mermaid@11.16.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.4 + '@mermaid-js/parser': 1.2.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.34.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.0) + cytoscape-fcose: 2.2.0(cytoscape@3.34.0) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.21 + dompurify: 3.4.11 + es-toolkit: 1.49.0 + katex: 0.16.47 + khroma: 2.1.0 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.4.0 + ts-dedent: 2.3.0 + uuid: 14.0.1 + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.2.0 @@ -4499,6 +5471,18 @@ snapshots: - bufferutil - utf-8-validate + miniflare@4.20260601.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.34.5 + undici: 7.24.8 + workerd: 1.20260601.1 + ws: 8.20.1 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + mrmime@2.0.1: {} ms@2.1.3: {} @@ -4584,6 +5568,8 @@ snapshots: dependencies: entities: 6.0.1 + path-data-parser@0.1.0: {} + path-to-regexp@6.3.0: {} pathe@2.0.3: {} @@ -4596,6 +5582,15 @@ snapshots: picomatch@4.0.3: {} + picomatch@4.0.4: {} + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + postcss-nested@6.2.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -4790,6 +5785,8 @@ snapshots: retext-stringify: 4.0.0 unified: 11.0.5 + robust-predicates@3.0.3: {} + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 @@ -4821,6 +5818,17 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + + rw@1.3.3: {} + + safer-buffer@2.1.2: {} + sax@1.4.3: {} semver@7.7.3: {} @@ -4914,6 +5922,10 @@ snapshots: space-separated-tokens@2.0.2: {} + starlight-markdown@0.1.5(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2)): + dependencies: + astro: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2) + starlight-sidebar-topics@0.6.2(@astrojs/starlight@0.37.1(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2))): dependencies: '@astrojs/starlight': 0.37.1(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2)) @@ -4954,6 +5966,8 @@ snapshots: dependencies: inline-style-parser: 0.2.7 + stylis@4.4.0: {} + supports-color@10.2.2: {} svgo@4.0.0: @@ -4972,13 +5986,15 @@ snapshots: tinyglobby@0.2.15: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 trim-lines@3.0.1: {} trough@2.2.0: {} + ts-dedent@2.3.0: {} + tsconfck@3.1.6(typescript@5.8.2): optionalDependencies: typescript: 5.8.2 @@ -5009,6 +6025,8 @@ snapshots: undici@7.24.4: {} + undici@7.24.8: {} + unenv@2.0.0-rc.24: dependencies: pathe: 2.0.3 @@ -5098,6 +6116,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@14.0.1: {} + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 @@ -5116,8 +6136,8 @@ snapshots: vite@6.4.1(@types/node@22.19.3): dependencies: esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 postcss: 8.5.6 rollup: 4.55.1 tinyglobby: 0.2.15 @@ -5145,6 +6165,14 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260401.1 '@cloudflare/workerd-windows-64': 1.20260401.1 + workerd@1.20260601.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260601.1 + '@cloudflare/workerd-darwin-arm64': 1.20260601.1 + '@cloudflare/workerd-linux-64': 1.20260601.1 + '@cloudflare/workerd-linux-arm64': 1.20260601.1 + '@cloudflare/workerd-windows-64': 1.20260601.1 + wrangler@4.80.0(@cloudflare/workers-types@4.20260405.1): dependencies: '@cloudflare/kv-asset-handler': 0.4.2 @@ -5162,6 +6190,22 @@ snapshots: - bufferutil - utf-8-validate + wrangler@4.97.0: + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260601.1) + blake3-wasm: 2.1.5 + esbuild: 0.27.3 + miniflare: 4.20260601.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260601.1 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 @@ -5170,6 +6214,8 @@ snapshots: ws@8.18.0: {} + ws@8.20.1: {} + xxhash-wasm@1.1.0: {} yargs-parser@21.1.1: {} diff --git a/public/_headers b/public/_headers index 23edcb1..7519807 100644 --- a/public/_headers +++ b/public/_headers @@ -3,3 +3,9 @@ Cross-Origin-Opener-Policy: same-origin Cross-Origin-Resource-Policy: cross-origin Referrer-Policy: strict-origin-when-cross-origin + Vary: Accept + Cache-Control: public, max-age=86400, stale-while-revalidate=86400 + +/docs/_astro/* + ! Cache-Control + Cache-Control: public, max-age=31536000, immutable diff --git a/public/assets/tty/keyboard-key-events.gif b/public/assets/tty/keyboard-key-events.gif new file mode 100644 index 0000000..a23b852 Binary files /dev/null and b/public/assets/tty/keyboard-key-events.gif differ diff --git a/public/assets/tty/keyboard-pointer-events.gif b/public/assets/tty/keyboard-pointer-events.gif new file mode 100644 index 0000000..0034013 Binary files /dev/null and b/public/assets/tty/keyboard-pointer-events.gif differ diff --git a/router/src/index.ts b/router/src/index.ts index 1703f08..d7c6e6a 100644 --- a/router/src/index.ts +++ b/router/src/index.ts @@ -1,23 +1,70 @@ -export interface Env {} +export interface Env { } + +// Where to proxy docs requests. In production this is the live site. On +// Cloudflare branch previews both Workers share the same branch slug +// (e.g. `fix-404-bombsh-docs-router` ↔ `fix-404-bombshell-docs`), so we point +// the router at the matching docs preview by rewriting our own hostname. +// Per-version previews use an 8-char hex id that differs per Worker and can't +// be mapped, so those fall back to production. +function docsOrigin(host: string): string { + const match = host.match(/^(.+)-bombsh-docs-router\.(.+\.workers\.dev)$/); + if (match) { + const [, slug, zone] = match; + if (!/^[0-9a-f]{8}$/.test(slug)) { + return `https://${slug}-bombshell-docs.${zone}/`; + } + } + return "https://docs.bomb.sh/"; +} + +// Bare project roots don't have their own index page and should redirect to +// their actual landing page instead of 404ing. +const PROJECT_LANDING_PAGES: Record = { + clack: "/docs/clack/basics/getting-started/", + tab: "/docs/tab/", + args: "/docs/args/getting-started/", + tty: "/docs/tty/basics/getting-started/", +}; export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { const url = new URL(request.url); + const projectMatch = url.pathname.match(/^\/docs\/([^/]+)\/?$/); + if (projectMatch) { + const landingPage = PROJECT_LANDING_PAGES[projectMatch[1]]; + if (landingPage && url.pathname !== landingPage) { + return Response.redirect(new URL(landingPage, url).toString(), 308); + } + } + if (url.pathname.startsWith("/docs")) { - const response = await fetch(new URL(url.pathname, "https://docs.bomb.sh/")); + const origin = docsOrigin(url.host); + let response = await fetch(new URL(url.pathname, docsOrigin(url.host))); + console.log({ from: url, to: new URL(url.pathname, docsOrigin(url.host)) }); + + + // Special case for Starlight's 404 page + let status = response.status; + if (status === 404) { + response = await fetch(new URL("/docs/404.html", origin)) + } + const headers = new Headers(response.headers); headers.set("Cross-Origin-Embedder-Policy", "require-corp"); headers.set("Cross-Origin-Opener-Policy", "same-origin"); headers.set("Cross-Origin-Resource-Policy", "cross-origin"); headers.set("Referrer-Policy", "strict-origin-when-cross-origin"); + + // If we got 404, return the HTML, but set status to 404 manually, + // because the response status would be 200 return new Response(response.body, { - status: response.status, - statusText: response.statusText, + status: status, + statusText: status === 404 ? "Not Found" : response.statusText, headers, }); } - return fetch(url); + return fetch(request); }, -} satisfies ExportedHandler; \ No newline at end of file +} satisfies ExportedHandler; diff --git a/scripts/generate-docs-index.ts b/scripts/generate-docs-index.ts new file mode 100644 index 0000000..a1608ab --- /dev/null +++ b/scripts/generate-docs-index.ts @@ -0,0 +1,161 @@ +/** + * Walks `src/content/docs` and emits `public/llms.txt` plus + * `public/docs-index.json` for agent discoverability and offline search. + */ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const rootDir = fileURLToPath(new URL('../', import.meta.url)); +const docsDir = path.join(rootDir, 'src/content/docs'); +const BASE_URL = 'https://bomb.sh/docs'; + +interface DocPage { + slug: string; + title: string; + description: string; + url: string; + markdownUrl: string; + template?: string; +} + +function stripQuotes(value: string): string { + if ( + (value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'")) + ) { + return value.slice(1, -1); + } + return value; +} + +function parseFrontmatter(content: string): Record { + const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/); + if (!match) return {}; + + const result: Record = {}; + for (const line of match[1].split('\n')) { + const kv = line.match(/^([\w-]+):\s*(.+)$/); + if (!kv) continue; + result[kv[1]] = stripQuotes(kv[2].trim()); + } + return result; +} + +function filePathToSlug(relativePath: string): string { + const withoutExt = relativePath.replace(/\.mdx?$/, ''); + if (withoutExt === 'index') return ''; + if (withoutExt.endsWith('/index')) { + return withoutExt.slice(0, -'/index'.length); + } + return withoutExt; +} + +function pageUrl(slug: string): string { + return slug ? `${BASE_URL}/${slug}/` : `${BASE_URL}/`; +} + +function markdownUrl(slug: string): string { + return slug ? `${BASE_URL}/${slug}/index.md` : `${BASE_URL}/index.md`; +} + +async function walkDocs(dir: string, base = ''): Promise { + const pages: DocPage[] = []; + const entries = await fs.readdir(dir, { withFileTypes: true }); + + for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) { + const rel = base ? `${base}/${entry.name}` : entry.name; + + if (entry.isDirectory()) { + pages.push(...(await walkDocs(path.join(dir, entry.name), rel))); + continue; + } + + if (!entry.name.endsWith('.mdx') && !entry.name.endsWith('.md')) { + continue; + } + + const content = await fs.readFile(path.join(dir, entry.name), 'utf8'); + const frontmatter = parseFrontmatter(content); + const slug = filePathToSlug(rel); + + pages.push({ + slug, + title: frontmatter.title ?? (slug || 'Untitled'), + description: frontmatter.description ?? '', + url: pageUrl(slug), + markdownUrl: markdownUrl(slug), + template: frontmatter.template, + }); + } + + return pages; +} + +function isIndexed(page: DocPage): boolean { + if (page.slug === '404') return false; + if (page.template === 'splash' && page.slug !== '') return false; + return true; +} + +function generateLlmsTxt(pages: DocPage[]): string { + const indexed = pages.filter(isIndexed); + const lines = [ + '# Bombshell Documentation', + '', + '> Effortlessly build beautiful command-line apps. Docs for Clack, Args, Tab, and TTY.', + '', + `Canonical docs: ${BASE_URL}/`, + '', + ]; + + const homepage = indexed.find((page) => page.slug === ''); + if (homepage) { + lines.push(`- [${homepage.title}](${homepage.url}): ${homepage.description}`, ''); + } + + const sections = new Map(); + for (const page of indexed) { + if (page.slug === '') continue; + const section = page.slug.split('/')[0]; + if (!sections.has(section)) sections.set(section, []); + sections.get(section)!.push(page); + } + + for (const [section, sectionPages] of [...sections.entries()].sort()) { + const label = section.charAt(0).toUpperCase() + section.slice(1); + lines.push(`## ${label}`, ''); + for (const page of sectionPages.sort((a, b) => a.slug.localeCompare(b.slug))) { + lines.push(`- [${page.title}](${page.url}): ${page.description}`); + } + lines.push(''); + } + + return `${lines.join('\n').trimEnd()}\n`; +} + +async function main() { + const pages = await walkDocs(docsDir); + const indexed = pages.filter(isIndexed); + + await fs.writeFile( + path.join(rootDir, 'public/docs-index.json'), + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + baseUrl: BASE_URL, + pages: indexed, + }, + null, + 2, + )}\n`, + ); + await fs.writeFile(path.join(rootDir, 'public/llms.txt'), generateLlmsTxt(pages)); + + console.log(`Generated docs index with ${indexed.length} pages`); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/src/assets/dark.svg b/src/assets/dark.svg index dfcd04d..6cb1d64 100644 --- a/src/assets/dark.svg +++ b/src/assets/dark.svg @@ -1,21 +1,4 @@ - diff --git a/src/assets/light.svg b/src/assets/light.svg index 9f8dd80..aa4c914 100644 --- a/src/assets/light.svg +++ b/src/assets/light.svg @@ -1,21 +1,4 @@ - diff --git a/src/assets/topics/args.svg b/src/assets/topics/args.svg new file mode 100644 index 0000000..41e31f9 --- /dev/null +++ b/src/assets/topics/args.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/topics/clack.svg b/src/assets/topics/clack.svg new file mode 100644 index 0000000..cab18c5 --- /dev/null +++ b/src/assets/topics/clack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/topics/tab.svg b/src/assets/topics/tab.svg new file mode 100644 index 0000000..41facc5 --- /dev/null +++ b/src/assets/topics/tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/topics/tty.svg b/src/assets/topics/tty.svg new file mode 100644 index 0000000..aa44d6e --- /dev/null +++ b/src/assets/topics/tty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/WebContainer/Terminal.astro b/src/components/WebContainer/Terminal.astro index c0a7f06..8a93e3f 100644 --- a/src/components/WebContainer/Terminal.astro +++ b/src/components/WebContainer/Terminal.astro @@ -17,6 +17,7 @@ docs-terminal { instance: Terminal | undefined; ro: ResizeObserver | undefined; updateSize = () => {}; + inputId = `docs-terminal-${crypto.randomUUID()}`; connectedCallback() { this.boot(); @@ -29,10 +30,16 @@ docs-terminal { this.ro = new ResizeObserver(() => this.updateSize()); this.ro.observe(this); } + labelHelperInput() { + const input = this.querySelector(".xterm-helper-textarea"); + input?.setAttribute("id", this.inputId); + input?.setAttribute("name", this.inputId); + } async boot() { if (this.instance) { this.instance.options.theme = theme; this.instance.open(this); + this.labelHelperInput(); return; } this.innerHTML = ""; @@ -52,6 +59,7 @@ docs-terminal { }); this.instance.open(this); + this.labelHelperInput(); const fit = new FitAddon(); this.instance.loadAddon(fit); diff --git a/src/content/docs/404.mdx b/src/content/docs/404.mdx new file mode 100644 index 0000000..11d3423 --- /dev/null +++ b/src/content/docs/404.mdx @@ -0,0 +1,10 @@ +--- +title: "404" +template: splash +editUrl: false +hero: + title: "404: Kaboom" + tagline: Page not found. It looks like this URL just took a direct hit. +prev: false +next: false +--- diff --git a/src/content/docs/clack/basics/getting-started.mdx b/src/content/docs/clack/basics/getting-started.mdx index 2f32fa1..a730c6e 100644 --- a/src/content/docs/clack/basics/getting-started.mdx +++ b/src/content/docs/clack/basics/getting-started.mdx @@ -88,6 +88,7 @@ async function main() { Clack provides several high-level components that make it easy to build interactive CLIs: - `text()` - For text input with validation +- `multiline()` - For multi-line text input - `password()` - For secure password input with masking - `select()` - For selection menus - `selectKey()` - For choosing an option by pressing its key diff --git a/src/content/docs/clack/packages/core.mdx b/src/content/docs/clack/packages/core.mdx index 731bdab..dd15a51 100644 --- a/src/content/docs/clack/packages/core.mdx +++ b/src/content/docs/clack/packages/core.mdx @@ -177,6 +177,7 @@ p.on('cancel', () => { - Character masking - Validation support - `clearOnError` option to reset on validation failure + - Empty submit resolves to `""`, matching `TextPrompt` and `Promise` (v1.4.2) 6. **MultiSelectPrompt**: For multiple selections - Checkbox interface @@ -201,7 +202,7 @@ p.on('cancel', () => { - Optional `separator` override for display - `minDate` / `maxDate` bounds and `DateParts` segment values -10. **Multi-line input**: v1.2.0 does not include a dedicated multi-line prompt in `@clack/core` or `@clack/prompts`. Use `text()` for a single line, an external editor or stdin for paragraphs, or extend `Prompt` for custom multi-line TTY behavior. +10. **Multi-line input**: Use [`multiline()`](/docs/clack/packages/prompts#multi-line-text) from `@clack/prompts` for multi-line text entry (since v1.3.0). `@clack/core` provides the underlying prompt primitive; extend `Prompt` directly only when you need custom multi-line TTY behavior. ## Layout utilities diff --git a/src/content/docs/clack/packages/prompts.mdx b/src/content/docs/clack/packages/prompts.mdx index e791964..bd416bc 100644 --- a/src/content/docs/clack/packages/prompts.mdx +++ b/src/content/docs/clack/packages/prompts.mdx @@ -165,13 +165,14 @@ Options: - `mask`: Character to use for masking input. Default: `'▪/•'`. - `validate`: A function or a [Standard Schema](https://github.com/standard-schema/standard-schema) that validates user input. If a custom function is given, you should return a `string` or `Error` to show as a validation error, or `undefined` to accept the result. - `clearOnError`: When enabled it causes the input to be cleared if/when validation fails. Default: `false`. +- Submitting with no input resolves to `""`, matching `text()` and the documented `Promise` return type (v1.4.2). - All [Common Options](#common-options) Common options (`withGuide`, `signal`, `input`, `output`) are also supported. ### Multi-line Text -The multi-line component accepts multiple lines of text input. By default, pressing Enter twice submits the input. +The multi-line component accepts multiple lines of text input. By default, pressing Enter twice **at the end of the input** submits; a double Enter elsewhere in the text adds a blank line instead (v1.4.2). ```ts twoslash import { multiline } from '@clack/prompts'; @@ -191,11 +192,14 @@ const bio = await multiline({ Options: -- `showSubmit`: When enabled it shows a `[ submit ]` button that can be focused with tab. By default, pressing Enter twice submits the input. Default: `false`. +- `showSubmit`: When enabled it shows a `[ submit ]` button that can be focused with tab. By default, pressing Enter twice at the end of the input submits. Default: `false`. +- `initialValue`: Pre-fills editable content when the prompt opens; the cursor is placed at the end (v1.4.2). See also [Text Options](#text-input). - All [Text Options](#text-input) ### Selection +`select`, `multiselect`, and `groupMultiselect` show persistent keyboard hint footers while active (v1.6.0), matching `autocomplete`. Pass `showInstructions: false` to hide them (v1.7.0). Default: `true`. + #### Simple value ```ts twoslash @@ -212,6 +216,30 @@ const framework = await select({ }); ``` +

+  Pick a framework
+   Next.js (React framework)
+  ○ Astro (Content-focused)
+  ○ SvelteKit (Compile-time framework)
+  ↑/↓ to navigate • Enter: confirm
+
+ +#### Hide instructions + +```ts twoslash +import { select } from '@clack/prompts'; + +const framework = await select({ + message: 'Pick a framework', + options: [ + { value: 'next', label: 'Next.js', hint: 'React framework' }, + { value: 'astro', label: 'Astro', hint: 'Content-focused' }, + { value: 'svelte', label: 'SvelteKit', hint: 'Compile-time framework' }, + ], + showInstructions: false, +}); +``` +

   Pick a framework
    Next.js (React framework)
@@ -290,6 +318,7 @@ const framework = await multiselect({
    Next.js (React framework)
    Astro (Content-focused)
   ◻ SvelteKit (Compile-time framework)
+  ↑/↓ to navigate • Space: select • Enter: confirm
 
### Select by key @@ -476,26 +505,30 @@ Options: ### Date input -`date` returns a `Date` on success or a cancel symbol. Use `format` to pick segment order: `YMD`, `MDY`, or `DMY`. Pass `locale` (BCP 47 string) to derive order and separators from `Intl`, or rely on the format alone. +The `date` prompt provides an interactive date picker, allowing users to navigate between year, month, and day segments and increment/decrement values using keyboard controls. ```ts twoslash -import { date, isCancel } from '@clack/prompts'; +import { date } from '@clack/prompts'; -const picked = await date({ - message: 'Pick a date', - format: 'YMD', - minDate: new Date('2026-01-01'), - maxDate: new Date('2026-12-31'), +const birthday = await date({ + message: 'Pick your birthday', + minDate: new Date('1900-01-01'), + initialValue: new Date(), + maxDate: new Date(), }); - -if (isCancel(picked)) { - process.exit(0); -} - -// picked is a Date ``` -Options include `defaultValue`, `initialValue`, `minDate`, `maxDate`, `validate`, and the usual `signal`, `input`, `output`, and `withGuide` settings. +Options: + +- `message`: The message or question shown to the user above the input. +- `format`: The date format to use (default: based on `locale`). +- `locale`: The [BCP 47 language tag](https://developer.mozilla.org/en-US/docs/Glossary/BCP_47_language_tag) to use for formatting. +- `defaultValue`: The default value returned when the user doesn't select a date. +- `initialValue`: The starting date shown when the prompt first renders. Users can edit this value before submitting. +- `minDate`: The minimum allowed date for validation. +- `maxDate`: The maximum allowed date for validation. +- `validate`: A function or a [Standard Schema](https://github.com/standard-schema/standard-schema) that validates user input. If a custom function is given, you should return a `string` or `Error` to show as a validation error, or `undefined` to accept the result.. +- All [Common Options](#common-options) ### Confirmation @@ -584,6 +617,7 @@ const projectOptions = await groupMultiselect({ │ ◻ Prettier (Code formatter) │ ◻ ESLint (Linter) Biome.js (Formatter and linter) + ↑/↓ to navigate • Space: select • Enter: confirm Options: @@ -596,6 +630,7 @@ Options: - `cursorAt`: The value the cursor should be positioned at initially. - `selectableGroups`: Whether entire groups can be selected at once (default: `true`). - `groupSpacing`: Number of blank lines between groups (default: `0`). +- `showInstructions`: Whether to show keyboard instructions below the option list (default: `true`) (v1.7.0). - All [Common Options](#common-options) ### Group @@ -701,6 +736,10 @@ intro('Welcome to clack');
  Welcome to clack
+Options: + +- All [Common Options](#common-options) + ### Outro The `outro` function defines the end of an interaction. @@ -716,6 +755,10 @@ outro('All operations are finished'); All operations are finished   +Options: + +- All [Common Options](#common-options) + ### Cancel The `cancel` function defines an interruption of an interaction and therefore its end. @@ -723,13 +766,19 @@ It accepts an optional string parameter which is displayed as a cancellation mes ```ts twoslash import { cancel } from '@clack/prompts'; +import process from 'node:process'; cancel('Installation canceled'); +process.exit(1); ```
  Installation canceled
  
+Options: + +- All [Common Options](#common-options) + ### Spinner The `spinner` function provides a loading indicator for long-running operations. @@ -899,6 +948,19 @@ note( ├───────────────────────────────────────╯ + + +```ts twoslash +import { note } from '@clack/prompts'; +import { styleText } from 'node:util'; + +note( + 'You can edit the file src/index.jsx', + 'Next steps.', + { format: (text) => styleText('dim', text) } +); +``` + The second parameter (the title) is optional. You can also provide a format function to customize how each line is displayed: ```ts twoslash @@ -1167,7 +1229,7 @@ await stream.step([ ### limitOptions -`limitOptions` trims a long option list to what fits the terminal, returning the lines to render and keeping the active index visible—intended for **custom** prompts that mirror Clack’s sliding window (see `@clack/prompts` source). Pass `options`, `cursor`, a `style` callback, optional `maxItems`, `columnPadding`, `rowPadding`, and `output` if not using `stdout`. +Trims an option list to what fits the terminal, while keeping the active option (cursor) visible using a Clack style sliding window. Returns the lines to render. ```ts twoslash import { limitOptions } from '@clack/prompts'; @@ -1177,8 +1239,18 @@ const options = ['apple', 'banana', 'cherry', 'date']; const lines = limitOptions({ options, cursor: 2, + maxItems: 8, style: (opt, active) => active ? styleText('cyan', opt) : styleText('dim', opt), - maxItems: 8, }); ``` + +Options: + +- `options`: The list of options to display. +- `cursor`: The index of the currently active/selected option. +- `style`: A function that styles the given option string. The `active` parameter indicates whether the option is currently selected. +- `maxItems`: Maximum number of options to display at once (default: `Infinity`). +- `columnPadding`: Number of columns to reserve for padding (default: `0`). +- `rowPadding`: Number of rows to reserve for padding (default: `0`). +- All [Common Options](#common-options) diff --git a/src/content/docs/tab/index.mdx b/src/content/docs/tab/index.mdx index 891521f..ea872ad 100644 --- a/src/content/docs/tab/index.mdx +++ b/src/content/docs/tab/index.mdx @@ -7,7 +7,9 @@ Shell autocompletions are largely missing in the JavaScript CLI ecosystem. tab p Additionally, tab supports autocompletions for `pnpm`, `npm`, `yarn`, and `bun`. -Modern CLI libraries like [Gunshi](https://github.com/kazupon/gunshi) include tab completion natively in their core. +Modern CLI libraries like [Gunshi](https://github.com/kazupon/gunshi) include tab completion natively in their core. + +Major CLIs and tooling projects including Cloudflare, Nuxt, Astro, and Vitest also adopted tab to provide shell completions for their users. As CLI tooling authors, if we can spare our users a second or two by not checking documentation or writing the `-h` flag, we're doing them a huge favor. The unconscious mind loves hitting the [TAB] key and always expects feedback. When nothing happens, it breaks the user's flow - a frustration apparent across the whole JavaScript CLI tooling ecosystem. @@ -15,6 +17,29 @@ tab solves this complexity by providing autocompletions that work consistently a ## Installation +### For Package Manager Completions + +Global install is recommended: + +```bash +npm install -g @bomb.sh/tab +``` + +Then enable completions permanently: + +```bash +# For zsh +echo 'source <(tab pnpm zsh)' >> ~/.zshrc +source ~/.zshrc + +# For bash +echo 'source <(tab pnpm bash)' >> ~/.bashrc +source ~/.bashrc + +``` + +### For CLI Library (Adding Completions to Your CLI) + ```bash npm install @bomb.sh/tab # or @@ -70,16 +95,56 @@ my-cli complete zsh > ~/.my-cli-completion.zsh echo 'source ~/.my-cli-completion.zsh' >> ~/.zshrc ``` +## Positional Arguments + +In addition to options, tab supports positional arguments with completion handlers: + +```typescript +// Root-level positional arg +t.argument('project', (complete) => { + complete('my-app', 'My application'); +}); + +// Command-level positional args +t.command('copy', 'Copy files') + .argument('source', (complete) => { + complete('src/', 'Source directory'); + complete('dist/', 'Distribution directory'); + }) + .argument('destination', (complete) => { + complete('build/', 'Build output'); + complete('release/', 'Release directory'); + }); + +// Variadic arguments (pass true as the third argument) +t.command('lint', 'Lint project').argument( + 'files', + (complete) => { + complete('src/', 'Source directory'); + complete('tests/', 'Tests directory'); + }, + true +); +``` + +Framework adapters infer positional arguments from your CLI framework definitions. See the [Commander.js integration](#commanderjs-integration) below for adapter-specific examples. + ## Package Manager Completions As mentioned earlier, tab provides completions for package managers as well: ```bash -# Generate and install completion scripts +# Generate and install completion scripts (requires global install) +tab pnpm zsh > ~/.pnpm-completion.zsh && echo 'source ~/.pnpm-completion.zsh' >> ~/.zshrc +tab npm bash > ~/.npm-completion.bash && echo 'source ~/.npm-completion.bash' >> ~/.bashrc +tab yarn fish > ~/.config/fish/completions/yarn.fish +tab bun powershell > ~/.bun-completion.ps1 && echo '. ~/.bun-completion.ps1' >> $PROFILE +``` + +Without a global install, use `npx`: + +```bash npx @bomb.sh/tab pnpm zsh > ~/.pnpm-completion.zsh && echo 'source ~/.pnpm-completion.zsh' >> ~/.zshrc -npx @bomb.sh/tab npm bash > ~/.npm-completion.bash && echo 'source ~/.npm-completion.bash' >> ~/.bashrc -npx @bomb.sh/tab yarn fish > ~/.config/fish/completions/yarn.fish -npx @bomb.sh/tab bun powershell > ~/.bun-completion.ps1 && echo '. ~/.bun-completion.ps1' >> $PROFILE ``` Example in action: @@ -92,6 +157,20 @@ yarn add --emoji= # Shows: true, false ``` +### Completing locally-installed CLIs + +Package manager completion does more than complete the package manager's own flags — it also **delegates to CLIs installed as local project dependencies**. If a CLI implements tab's completion protocol (directly or via a [framework adapter](#framework-adapters)), it becomes completable through your package manager _without_ being on your `PATH` and without installing its completion script separately: + +```bash +pnpm exec my-cli # completes my-cli's subcommands and flags +pnpm dlx my-cli +pnpm my-cli # the bare form works too +``` + +Under the hood, tab strips the package-manager wrapper (`exec`, `x`, `run`, `dlx`), detects whether the target CLI supports completion, and forwards the request to it — falling back to running the CLI _through_ the package manager (e.g. `pnpm my-cli complete -- …`) so locally-installed binaries resolve. The same works for `npm exec`, `yarn`, and `bun x`. + +Completion is registered against the package-manager binary (`npm`, `pnpm`, `yarn`, `bun`). `npx` and `bunx` are separate commands with no completion of their own, so `npx my-cli ` / `bunx my-cli ` won't complete — use `npm exec my-cli` / `bun x my-cli` instead. + ## Framework Adapters tab provides adapters for popular JavaScript CLI frameworks. @@ -165,26 +244,44 @@ cli(); ### Commander.js Integration ```typescript -import { Command } from 'commander'; +import { Command, Option } from 'commander'; import tab from '@bomb.sh/tab/commander'; const program = new Command('my-cli'); program.version('1.0.0'); -// Define commands +// Options with .choices() get completions automatically +program.addOption( + new Option('-l, --logLevel ', 'Specify log level').choices([ + 'info', + 'warn', + 'error', + 'silent', + ]) +); + program .command('serve') .description('Start the server') .option('-p, --port ', 'port to use', '3000') .option('-H, --host ', 'host to use', 'localhost') - .action((options) => { + .action(() => { console.log('Starting server...'); }); +program + .command('lint [files...]') + .description('Lint source files') + .option('--fix', 'automatically fix problems'); + +program + .command('copy ') + .description('Copy files'); + // Initialize tab completions const completion = tab(program); -// Add custom completions +// Custom option completions const serveCommand = completion.commands.get('serve'); const portOption = serveCommand?.options.get('port'); if (portOption) { @@ -194,9 +291,36 @@ if (portOption) { }; } +// Custom positional argument completions +const lintCommand = completion.commands.get('lint'); +const filesArg = lintCommand?.arguments.get('files'); +if (filesArg) { + filesArg.handler = (complete) => { + complete('main.ts', 'Main file'); + complete('index.ts', 'Index file'); + }; +} + +const copyCommand = completion.commands.get('copy'); +const sourceArg = copyCommand?.arguments.get('source'); +if (sourceArg) { + sourceArg.handler = (complete) => { + complete('src/', 'Source directory'); + complete('dist/', 'Distribution directory'); + }; +} + program.parse(); ``` +Options defined with Commander's `.choices()` are picked up automatically — no custom handler needed. For positional arguments, the adapter reads argument definitions from your commands; add handlers via `arguments.get('name')` when you need custom suggestions. + +The Commander integration supports customising the command name used to generate shell completion scripts. The default is `complete`. If you use a custom name like `completion`, it appears in help as `completion `, while runtime suggestions stay on the hidden `complete -- [args...]` command. Use your custom command when generating shell scripts: + +```javascript +const completion = tab(program, { completionCommandName: 'completion' }); +``` + ## How It Works tab uses a standardized completion protocol that any CLI can implement: diff --git a/src/content/docs/tty/api/index.mdx b/src/content/docs/tty/api/index.mdx new file mode 100644 index 0000000..d805e5f --- /dev/null +++ b/src/content/docs/tty/api/index.mdx @@ -0,0 +1,46 @@ +--- +title: API Overview +description: Overview of the @bomb.sh/tty public API +--- + +`@bomb.sh/tty` exports five modules from a single entry point. Everything is available from `@bomb.sh/tty`: + +```ts twoslash +import { + open, text, close, snapshot, rgba, fit, grow, percent, fixed, + createTerm, + createInput, + settings, alternateBuffer, cursor, mouseTracking, +} from "@bomb.sh/tty"; +``` + +## Modules + +The module split mirrors the zero-I/O [architecture](/docs/tty/basics/getting-started#architecture): ops describe frames, term and input are the two pipelines, and settings/termcodes build the escape bytes you write to the terminal yourself. + +| Module | Description | +|---|---| +| [Ops](/docs/tty/api/ops) | UI directive builders: `open`, `text`, `close`, sizing, colors, transitions | +| [Term](/docs/tty/api/term) | Renderer: `createTerm`, `render`, pointer events, layout info | +| [Input](/docs/tty/api/input) | Input parser: `createInput`, `scan`, keyboard/mouse/resize events | +| [Settings](/docs/tty/api/settings) | Terminal mode helpers: alternate buffer, cursor, mouse tracking | +| [Termcodes](/docs/tty/api/termcodes) | Low-level ANSI escape sequence bytes | + +## Typical app structure + +1. Apply [settings](/docs/tty/api/settings) to stdout (alternate buffer, cursor, mouse) +2. Create a [term](/docs/tty/api/term) and [input](/docs/tty/api/input) instance +3. Set stdin to raw mode +4. On each frame: build [ops](/docs/tty/api/ops) → `term.render()` → write `output` +5. On stdin data: `input.scan()` → handle events +6. If `renderResult.animating`, schedule another frame +7. On exit: revert settings and restore terminal state + +## Deno-only exports + +The Deno source tree includes `@bomb.sh/tty/validate` with runtime op validation (`validate`, `assert`, `validated`). This subpath is not in the published npm `exports` map for v0.8.0. + +## Next steps + +- [Getting Started](/docs/tty/basics/getting-started) +- [Examples](/docs/tty/guides/examples) diff --git a/src/content/docs/tty/api/input.mdx b/src/content/docs/tty/api/input.mdx new file mode 100644 index 0000000..b70d638 --- /dev/null +++ b/src/content/docs/tty/api/input.mdx @@ -0,0 +1,127 @@ +--- +title: Input +description: Terminal input parser API for @bomb.sh/tty +--- + +import { Aside } from '@astrojs/starlight/components'; + +The input module decodes raw terminal bytes into structured events. All parsing logic lives in WASM. The TypeScript layer is a thin wrapper. See [Architecture](/docs/tty/basics/getting-started#architecture) for why parsing is pure computation and reading stdin is up to you. + +## createInput(options?) + +Creates an input parser instance. + +```ts twoslash +import { createInput } from "@bomb.sh/tty"; + +async function main() { + let input = await createInput({ escLatency: 25 }); +} +``` + +### InputOptions + +| Option | Type | Default | Description | +|---|---|---|---| +| `escLatency` | `number` | `25` | Milliseconds to wait before resolving a lone ESC as the Escape key | +| `terminfo` | `Uint8Array` | xterm defaults | Compiled terminfo binary for terminal-specific sequences | + + + +## input.scan(bytes?) + +Feed raw bytes from stdin and return parsed events. Call with no arguments to flush a pending ESC after the latency period. + +```ts twoslash +import { createInput } from "@bomb.sh/tty"; + +async function main() { + let input = await createInput({ escLatency: 25 }); + + process.stdin.setRawMode(true); + let timer: ReturnType | undefined; + + process.stdin.on("data", (buf) => { + clearTimeout(timer); + + let { events, pending } = input.scan(new Uint8Array(buf)); + + for (let event of events) { + console.log(event); + } + + if (pending) { + timer = setTimeout(() => { + let flush = input.scan(); + for (let event of flush.events) { + console.log(event); + } + }, pending.delay); + } + }); +} +``` + +### ScanResult + +| Property | Type | Description | +|---|---|---| +| `events` | `InputEvent[]` | Events produced from this scan | +| `pending` | `{ delay: number }` | Present when a lone ESC is buffered. Re-call `scan()` after `delay` ms | + +## Event types + +### Keyboard events + +| Type | Description | +|---|---| +| `keydown` | Key was pressed | +| `keyrepeat` | Key auto-repeat (Kitty enhancement level 2+) | +| `keyup` | Key was released (Kitty enhancement level 2+) | + +All keyboard events include: + +| Property | Type | Description | +|---|---|---| +| `key` | `string` | Key value (e.g. `"a"`, `"Enter"`, `"ArrowUp"`) | +| `code` | `KeyCode` | Physical key identity (US PC-101 layout) | +| `text` | `string?` | Typed character, if applicable | +| `shifted` | `string?` | Shifted character variant | +| `alt`, `ctrl`, `shift` | `true?` | Modifier keys held | + +### Mouse events + +| Type | Description | +|---|---| +| `mousedown` | Button pressed (`left`, `right`, `middle`) | +| `mouseup` | Button released | +| `mousemove` | Movement while button held | +| `wheel` | Scroll wheel (`direction: "up"` \| `"down"`) | + +Mouse events include `x` and `y` coordinates (0-based) and optional modifiers. + +### Other events + +| Type | Description | +|---|---| +| `resize` | Terminal resized. Returns `{ width, height }` | +| `cursor` | DSR cursor position report. Returns `{ row, column }` (1-based) | + +Pointer events (`pointerenter`, `pointerleave`, `pointerclick`) are produced by the [renderer](/docs/tty/api/term), not the input parser. + +## Supported protocols + +The parser recognizes: + +- VT/ANSI escape sequences +- UTF-8 codepoints +- Mouse protocols (VT200, SGR, urxvt) +- Progressive keyboard protocol (via [settings](/docs/tty/api/settings)) +- Partial sequence reassembly across read boundaries + +## Next steps + +- [Settings API](/docs/tty/api/settings) (enable mouse tracking and keyboard protocols) +- [Term API](/docs/tty/api/term) (pointer hit testing on the render side) diff --git a/src/content/docs/tty/api/ops.mdx b/src/content/docs/tty/api/ops.mdx new file mode 100644 index 0000000..89fb632 --- /dev/null +++ b/src/content/docs/tty/api/ops.mdx @@ -0,0 +1,168 @@ +--- +title: Ops +description: UI directive builders for @bomb.sh/tty +--- + +import { Aside } from '@astrojs/starlight/components'; + +The ops module provides builders for describing terminal UI as a flat array of directives. Each frame is a complete snapshot. Build ops, pass them to [`term.render()`](/docs/tty/api/term), and write the output bytes. + +## Building a frame + +```ts twoslash +import { close, open, rgba, text, grow } from "@bomb.sh/tty"; + +let ops = [ + open("root", { + layout: { width: grow(), height: grow(), direction: "ttb" }, + }), + open("panel", { + layout: { padding: { left: 1, right: 1, top: 1, bottom: 1 } }, + border: { color: rgba(0, 255, 0), left: 1, right: 1, top: 1, bottom: 1 }, + cornerRadius: { tl: 1, tr: 1, bl: 1, br: 1 }, + }), + text("Hello, World!"), + close(), + close(), +]; +``` + +## open(id, props?) + +Opens a layout element. Every element needs a unique string `id` for pointer hit-testing and layout queries. + +### Layout + +| Property | Type | Description | +|---|---|---| +| `width` | `SizingAxis` | Horizontal sizing (`fit`, `grow`, `percent`, `fixed`) | +| `height` | `SizingAxis` | Vertical sizing | +| `padding` | `{ left?, right?, top?, bottom? }` | Inner padding in cells | +| `gap` | `number` | Gap between children | +| `direction` | `"ltr"` \| `"ttb"` | Child layout direction | +| `alignX` | `"left"` \| `"center"` \| `"right"` | Horizontal alignment | +| `alignY` | `"top"` \| `"center"` \| `"bottom"` | Vertical alignment | + +### Style + +| Property | Type | Description | +|---|---|---| +| `bg` | `number` | Background color (packed RGBA via `rgba()`) | +| `cornerRadius` | `{ tl?, tr?, bl?, br? }` | Rounded corners | +| `border` | `{ color, bg?, left?, right?, top?, bottom? }` | Border sides (number or `{ width, color?, bg? }`) | +| `clip` | `{ horizontal?, vertical? }` | Clip overflowing content | + +### Floating + +| Property | Type | Description | +|---|---|---| +| `floating.x`, `floating.y` | `number` | Position offset | +| `floating.expand` | `{ width?, height? }` | Expand floating bounds | +| `floating.attachTo` | `"none"` \| `"parent"` \| `"element"` \| `"root"` | Attachment target | +| `floating.attachPoints` | `{ element?, parent? }` | Anchor points | +| `floating.pointerCaptureMode` | `"capture"` \| `"passthrough"` | Pointer event capture | +| `floating.clipTo` | `"none"` \| `"attached-parent"` | Clip to attached parent | +| `floating.zIndex` | `number` | Stacking order | + +### Transitions + +```ts twoslash +import { open, rgba } from "@bomb.sh/tty"; + +open("sidebar", { + layout: { width: { type: "fixed", value: 20 } }, + bg: rgba(30, 30, 40), + transition: { + duration: 0.3, + easing: "easeInOut", + properties: ["width", "bg"], + }, +}); +``` + +| Property | Type | Description | +|---|---|---| +| `duration` | `number` | Duration in seconds | +| `easing` | `"linear"` \| `"easeIn"` \| `"easeOut"` \| `"easeInOut"` | Easing function | +| `properties` | `TransitionProperty[]` | Properties to animate | +| `interactive` | `boolean` | Allow interaction during transition | + +Transition properties: `"x"`, `"y"`, `"position"`, `"width"`, `"height"`, `"size"`, `"bg"`, `"overlay"`, `"borderColor"`, `"borderWidth"`, `"all"`. + +## text(content, props?) + +Renders a text node inside the current open element. + +| Property | Type | Description | +|---|---|---| +| `color` | `number` | Foreground color | +| `bg` | `number` | Background color | +| `fontSize` | `number` | Font size | +| `fontId` | `number` | Font identifier | +| `wrap` | `number` | Wrap width | +| `attrs` | `number` | Text attributes (bold, italic, etc.) | + +## close() + +Closes the current open element. Ops must be properly nested. Every `open` needs a matching `close`. + +## snapshot(ops) + +Pre-packs an op array into a reusable snapshot op. Useful when part of the UI is static across frames. + +```ts twoslash +import { close, open, snapshot, text, grow } from "@bomb.sh/tty"; + +let chrome = snapshot([ + open("header", { layout: { width: grow(), height: { type: "fixed", value: 1 } } }), + text("My App"), + close(), +]); + +// Each frame: [chrome, ...dynamicOps] +``` + +## rgba(r, g, b, a?) + +Packs an RGBA color into a 32-bit integer. Alpha defaults to 255. + +```ts twoslash +import { rgba } from "@bomb.sh/tty"; + +rgba(255, 0, 0); // red +rgba(0, 255, 0, 128); // semi-transparent green +``` + +## Sizing helpers + +```ts twoslash +import { fit, grow, percent, fixed } from "@bomb.sh/tty"; + +fit(); // shrink to content +fit(10, 40); // fit with min/max +grow(); // expand to fill available space +grow(5, 50); // grow with min/max +percent(0.5); // 50% of parent +fixed(20); // exactly 20 cells +``` + +## Types + +| Type | Description | +|---|---| +| `Op` | Union of all directive types | +| `OpenElement` | Element opened by `open()` | +| `Text` | Text node | +| `CloseElement` | Element closed by `close()` | +| `SizingAxis` | `{ type: "fit" \| "grow" \| "percent" \| "fixed", ... }` | +| `Transition` | Transition configuration | +| `BorderSide` | `number` or `{ width, color?, bg? }` | + + + +## Next steps + +- [Term API](/docs/tty/api/term) (rendering ops to the terminal) +- [Examples](/docs/tty/guides/examples) (transitions and layout demos) diff --git a/src/content/docs/tty/api/settings.mdx b/src/content/docs/tty/api/settings.mdx new file mode 100644 index 0000000..cfbb55f --- /dev/null +++ b/src/content/docs/tty/api/settings.mdx @@ -0,0 +1,142 @@ +--- +title: Settings +description: Terminal mode helpers for @bomb.sh/tty +--- + +The settings module provides composable terminal mode changes. Each setting produces `apply` and `revert` byte sequences you write to stdout. + +## `Setting` + +Every setting helper returns: + +```ts +interface Setting { + apply: Uint8Array; + revert: Uint8Array; +} +``` + +Write `apply` on startup and `revert` on exit to restore the terminal. + +## `settings(...sequence)` + +Compose multiple settings into one. Revert runs in reverse order. + +```ts twoslash +import { + alternateBuffer, + cursor, + mouseTracking, + settings, +} from "@bomb.sh/tty"; + +let tty = settings( + alternateBuffer(), + cursor(false), + mouseTracking(), +); + +process.stdout.write(tty.apply); + +// on exit: +process.stdout.write(tty.revert); +``` + +## `alternateBuffer(options?)` + +Switch to the alternate screen buffer. + +| Option | Type | Default | Description | +|---|---|---|---| +| `clear` | `boolean` | `true` | Clear the alternate buffer on entry | + +```ts twoslash +import { alternateBuffer } from "@bomb.sh/tty"; + +alternateBuffer(); // enter, clear +alternateBuffer({ clear: false }); // enter, preserve contents +``` + +Revert switches back to the main screen with scrollback intact. + +## `cursor(visible)` + +Show or hide the terminal cursor (DEC private mode 25). + +```ts twoslash +import { cursor } from "@bomb.sh/tty"; + +cursor(false); // hide +cursor(true); // show +``` + +## `saveCursorPosition()` + +Save and restore cursor position using DECSC (`ESC 7`) / DECRC (`ESC 8`). + +```ts twoslash +import { saveCursorPosition } from "@bomb.sh/tty"; + +let pos = saveCursorPosition(); +process.stdout.write(pos.apply); +// ... render ... +process.stdout.write(pos.revert); +``` + +## `progressiveInput(level)` + +Enable the progressive keyboard enhancement protocol. + +```ts twoslash +import { progressiveInput } from "@bomb.sh/tty"; + +progressiveInput(2); // Kitty enhancement level 2+ +``` + +Revert sends `CSI +Line mode (`mode: "line"`) renders into a region of the main screen scrollback instead of the alternate buffer. See the [inline regions example](https://github.com/bombshell-dev/tty/blob/main/examples/inline-regions/index.ts). + + +## Next steps + +- [Ops API](/docs/tty/api/ops) (building UI directives) +- [Input API](/docs/tty/api/input) (parsing stdin events) diff --git a/src/content/docs/tty/api/termcodes.mdx b/src/content/docs/tty/api/termcodes.mdx new file mode 100644 index 0000000..64a9985 --- /dev/null +++ b/src/content/docs/tty/api/termcodes.mdx @@ -0,0 +1,76 @@ +--- +title: Termcodes +description: Low-level ANSI escape sequence builders for @bomb.sh/tty +--- + +import { Aside } from '@astrojs/starlight/components'; + +The termcodes module provides low-level escape sequence builders. Each function returns a `Uint8Array` you can write directly to stdout. + + + +## ESC(str) + +Encode a plain escape sequence. Prepends `ESC` (`\x1b`) to the given string. + +```ts twoslash +import { ESC } from "@bomb.sh/tty"; + +process.stdout.write(ESC("7")); // save cursor (DECSC) +``` + +## CSI(str) + +Encode a Control Sequence Introducer command. Prepends `ESC[` to the given string. + +```ts twoslash +import { CSI } from "@bomb.sh/tty"; + +process.stdout.write(CSI("2J")); // clear screen +``` + +## DSR() + +Request cursor position via Device Status Report. Sends `CSI 6n`. The terminal responds with a Cursor Position Report (`CSI row ; column R`) where row and column are 1-based. + +```ts twoslash +import { DSR } from "@bomb.sh/tty"; + +process.stdout.write(DSR()); +``` + +The response is parsed as a `cursor` event by the [input parser](/docs/tty/api/input). Used by the [inline regions example](https://github.com/bombshell-dev/tty/blob/main/examples/inline-regions/index.ts) to place animated output in scrollback. + +## SHOWCURSOR() / HIDECURSOR() + +Show or hide the cursor (DEC private mode 25, DECTCEM). + +```ts twoslash +import { HIDECURSOR, SHOWCURSOR } from "@bomb.sh/tty"; + +process.stdout.write(HIDECURSOR()); +process.stdout.write(SHOWCURSOR()); +``` + +Equivalent to [`cursor(false)`](/docs/tty/api/settings) / [`cursor(true)`](/docs/tty/api/settings). + +## ALTSCREEN(options?) / MAINSCREEN() + +Switch between main and alternate screen buffers. + +```ts twoslash +import { ALTSCREEN, MAINSCREEN } from "@bomb.sh/tty"; + +process.stdout.write(ALTSCREEN()); // enter, clear +process.stdout.write(ALTSCREEN({ clear: false })); // enter, preserve +process.stdout.write(MAINSCREEN()); // return to main screen +``` + +Equivalent to [`alternateBuffer()`](/docs/tty/api/settings) / its revert sequence. + +## Next steps + +- [Settings API](/docs/tty/api/settings) (composable terminal mode helpers) +- [Getting Started](/docs/tty/basics/getting-started) diff --git a/src/content/docs/tty/basics/getting-started.mdx b/src/content/docs/tty/basics/getting-started.mdx new file mode 100644 index 0000000..da203c8 --- /dev/null +++ b/src/content/docs/tty/basics/getting-started.mdx @@ -0,0 +1,252 @@ +--- +title: Getting Started +description: Learn how to get started with @bomb.sh/tty +--- + +import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; + +`@bomb.sh/tty` is a low-level, platform-independent terminal renderer and event parser for JavaScript. Use it directly to build full-screen or inline terminal UIs, or as the foundation for your own framework. + + + +## Features + +- **Declarative terminal UI:** Flexbox-like layout powered by [Clay](https://github.com/nicbarker/clay), with borders, colors, floating elements, scroll containers, and pointer hit-testing +- **Zero I/O:** Never reads stdin or writes stdout. Feed bytes in, get bytes and events back +- **Runs everywhere:** The entire engine is compiled to WebAssembly with no native dependencies for consumers + +## When to use it + +Reach for `@bomb.sh/tty` when you need a **rendering engine** for terminal UI: layout, styling, diffing, and input parsing, without committing to a particular app framework or I/O model. + +### Good fits + +- **Full-screen applications:** Dashboards, tools, and games that take over the alternate screen buffer with layouts, borders, mouse hover, and keyboard input (see the [2048](/docs/tty/guides/examples) and [keyboard](/docs/tty/guides/examples) demos) +- **Inline animated output:** Spinners, progress bars, or live status regions embedded in normal scrollback without switching to a full-screen mode (see [inline regions](/docs/tty/guides/examples)) +- **Rich, structured output:** Diff views, panels, sidebars, and multi-pane layouts where hand-written ANSI becomes unmaintainable +- **Interactive layouts with pointer support:** Hover states, clickable regions, and drag-style interactions driven by terminal mouse reporting +- **Animated UI:** Transitions on width, color, position, and other properties with efficient cell-level diffing between frames +- **Custom TUI frameworks:** Zero I/O means you wire stdin/stdout (or any byte stream) yourself; the engine stays a pure compute layer you can embed in Node, Deno, Bun, or the browser + +### When to pick something else + +- **One-shot CLI prompts** (text input, selects, confirms): use [`@clack/prompts`](/docs/clack/basics/getting-started); it targets a different problem and uses Node's built-in `tty` module, not this package +- **Component-based UI with state and bindings:** use `@clack/ui`, which is built on `@bomb.sh/tty` and handles the higher-level framework concerns for you + +## Requirements + +Node >= 22. Also works in Deno, Bun, and browsers. + +## Installation + + + + ```bash + npm install @bomb.sh/tty + ``` + + + ```bash + pnpm add @bomb.sh/tty + ``` + + + ```bash + yarn add @bomb.sh/tty + ``` + + + +## Core concepts + +**Frames as snapshots.** Each frame is a complete, independent UI description. Build an array of ops (`open`, `text`, `close`), pass it to `term.render()`, and write the returned ANSI bytes to stdout. The renderer carries layout and diff state between frames, not a persistent component tree. + +**Zero I/O boundary.** You own stdin/stdout. `@bomb.sh/tty` is pure computation: one WASM call per frame on the output side, and a byte-stream parser on the input side. + +**Efficient output.** Clay runs layout, walks render commands into a cell buffer, and diffs against the previous frame. Only changed cells produce ANSI escape sequences. + +## Architecture + +The whole design follows from one principle: **zero I/O**. The engine never reads stdin or writes stdout, you feed it bytes and it hands bytes back. Because the WASM module is pure computation with no I/O, it runs anywhere WebAssembly does: Node, Deno, Bun, or the browser, and it can serve as the foundation for higher-level frameworks. + +That principle splits the system into two independent data flows: an **output pipeline** that turns your UI description into ANSI bytes, and an **input pipeline** that turns raw terminal bytes into structured events. Your app sits on the outside, owning all I/O: + +```mermaid +flowchart LR + subgraph app ["Your app (owns I/O)"] + Stdin["stdin.read"] + Loop["event loop"] + Stdout["stdout.write"] + end + subgraph tty ["@bomb.sh/tty (pure computation)"] + Term["term.render"] + Input["input.scan"] + Settings["settings / termcodes"] + end + Loop -->|"ops"| Term + Term -->|"ANSI bytes"| Stdout + Stdin -->|"raw bytes"| Input + Input -->|"events"| Loop + Settings -->|"mode bytes"| Stdout +``` + +### Output + +```mermaid +flowchart LR + subgraph ts [TypeScript] + Ops["UI ops"] + Stdout["stdout.write"] + end + subgraph wasm [WASM] + Clay["Clay layout"] + Diff["Cell diff"] + Esc["Escape bytes"] + end + Ops -->|"Uint32Array"| Clay + Clay --> Diff + Diff --> Esc + Esc -->|"ANSI bytes"| Stdout +``` + +Each frame's ops flatten into a single `Uint32Array` sent to WASM in one call. Clay performs layout, walks the render commands into a cell buffer, and diffs it against the previous frame. Only changed cells become ANSI escape sequences, so stdout writes stay small even for busy full-screen UIs. + +### Input + +```mermaid +flowchart LR + subgraph ts [TypeScript] + Stdin["stdin.read"] + Events["InputEvent[]"] + end + subgraph wasm [WASM] + Parse["Trie match"] + Decode["UTF-8 / mouse / ESC"] + end + Stdin -->|"raw bytes"| Parse + Parse --> Decode + Decode --> Events +``` + +Raw bytes are fed into a WASM parser that recognizes VT/ANSI escape sequences, UTF-8 codepoints, and mouse protocols. Partial sequences that arrive across read boundaries are reassembled automatically. A lone ESC byte is held for a configurable latency window (default 25ms) before being emitted. + +### Why the API is split this way + +Each of the five [API modules](/docs/tty/api/) maps directly onto this architecture: + +- **[Ops](/docs/tty/api/ops):** Pure data builders that describe a frame. Calling `open`, `text`, or `close` has no side effects — it only produces the directives the output pipeline consumes +- **[Term](/docs/tty/api/term):** The output pipeline. Ops go in; ANSI bytes and pointer events come out +- **[Input](/docs/tty/api/input):** The input pipeline. Raw bytes go in; structured keyboard and mouse events come out +- **[Settings](/docs/tty/api/settings) and [Termcodes](/docs/tty/api/termcodes):** Because you own stdin/stdout, you also own terminal state. These build the escape bytes to apply and revert modes (alternate buffer, cursor, mouse tracking) yourself + +Every module is either pure computation or byte construction — none of them touches I/O. That's what keeps the whole API surface identical across runtimes, and what lets you swap `process.stdout` for any byte sink you like. + +## Quick start: rendering + +To render this: + +``` +╭───────────────╮ +│ Hello, World! │ +╰───────────────╯ +``` + +```ts twoslash +import { close, createTerm, grow, open, rgba, text } from "@bomb.sh/tty"; + +async function main() { + let term = await createTerm({ width: 80, height: 24 }); + + let { output } = term.render([ + open("root", { + layout: { width: grow(), height: grow(), direction: "ttb" }, + }), + open("greeting", { + layout: { padding: { left: 1, right: 1, top: 1, bottom: 1 } }, + border: { + color: rgba(0, 255, 0), + left: 1, right: 1, top: 1, bottom: 1, + }, + cornerRadius: { tl: 1, tr: 1, bl: 1, br: 1 }, + }), + text("Hello, World!"), + close(), + close(), + ]); + + process.stdout.write(output); +} +``` + +## Quick start: input + +```ts twoslash +import { createInput } from "@bomb.sh/tty"; + +async function main() { + let input = await createInput({ escLatency: 25 }); + + process.stdin.setRawMode(true); + let timer: ReturnType | undefined; + + process.stdin.on("data", (buf) => { + clearTimeout(timer); + + let { events, pending } = input.scan(new Uint8Array(buf)); + + for (let event of events) { + console.log(event); + } + + if (pending) { + timer = setTimeout(() => { + let flush = input.scan(); + for (let event of flush.events) { + console.log(event); + } + }, pending.delay); + } + }); +} +``` + +## Quick start: terminal modes + +Use composable settings to enter alternate buffer mode, hide the cursor, and enable mouse tracking: + +```ts twoslash +import { + alternateBuffer, + cursor, + mouseTracking, + settings, +} from "@bomb.sh/tty"; + +let tty = settings(alternateBuffer(), cursor(false), mouseTracking()); +process.stdout.write(tty.apply); + +// on exit: +process.stdout.write(tty.revert); +``` + +## Demos + +The input parser decodes raw terminal bytes into structured events. Here you can see each key event as the string "hello world" is typed: + +![Keyboard events demo](/docs/assets/tty/keyboard-key-events.gif) + +Hover styles applied to UI elements in response to pointer state. Clay drives hit testing, so you don't need manual coordinate math: + +![Pointer events demo](/docs/assets/tty/keyboard-pointer-events.gif) + +## Next steps + +1. Explore [runnable examples](/docs/tty/guides/examples) on GitHub +2. Read the [Ops API](/docs/tty/api/ops) for layout and styling directives +3. Join our [Discord community](https://bomb.sh/chat) for support and discussions diff --git a/src/content/docs/tty/guides/examples.mdx b/src/content/docs/tty/guides/examples.mdx new file mode 100644 index 0000000..a6f04d4 --- /dev/null +++ b/src/content/docs/tty/guides/examples.mdx @@ -0,0 +1,120 @@ +--- +title: Examples +description: Runnable @bomb.sh/tty demos and what to learn from each +--- + +import { Aside } from '@astrojs/starlight/components'; + +The best way to learn `@bomb.sh/tty` after the [getting started guide](/docs/tty/basics/getting-started) is to run the demos in the [tty repository](https://github.com/bombshell-dev/tty). Each one is a small app that shows how the pieces fit together: render loop, input parsing, terminal modes, transitions. + + + +## Get set up + +```bash +git clone https://github.com/bombshell-dev/tty.git +cd tty +make # build the WASM bundle +node examples/keyboard/index.ts +``` + + + +## Which demo should I run? + +| Demo | Start here if you want to… | Key APIs | +|---|---|---| +| [Keyboard](#keyboard) | Wire up input, pointer hover, and terminal modes | [`createInput`](/docs/tty/api/input), [`settings`](/docs/tty/api/settings), [`render` pointer option](/docs/tty/api/term) | +| [Transitions](#transitions) | Animate layout and color between frames | [`open` transitions](/docs/tty/api/ops), [`animating`](/docs/tty/api/term) | +| [Inline regions](#inline-regions) | Draw animated output in scrollback, not full-screen | [`render` line mode](/docs/tty/api/term), [`DSR`](/docs/tty/api/termcodes) | +| [2048](#2048) | See everything combined in a real app | ops, term, input, settings | +| [Diff](#diff) | Highlight per-glyph in a layout | [`text` `bg`](/docs/tty/api/ops) | + +**Suggested order:** keyboard → transitions → inline regions → 2048. Diff is a focused layout exercise you can skip until you need it. + +## Keyboard + +[`examples/keyboard/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/keyboard/index.ts) + +```bash +node examples/keyboard/index.ts +``` + +This is the best first demo. It shows the full loop most apps follow: + +1. Apply [terminal settings](/docs/tty/api/settings) (alternate buffer, hidden cursor, mouse tracking) +2. Create a [term](/docs/tty/api/term) and feed [pointer state](/docs/tty/api/term) each frame +3. Parse stdin through [`createInput`](/docs/tty/api/input) and dispatch events +4. Revert settings on exit + +Type on the keyboard to see decoded key events. Move the mouse to see hover styles. Clay handles hit testing, so you don't need manual coordinate math. + +![Keyboard events demo](/docs/assets/tty/keyboard-key-events.gif) + +![Pointer events demo](/docs/assets/tty/keyboard-pointer-events.gif) + +## Transitions + +[`examples/transitions/sidebar.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/transitions/sidebar.ts) · [`examples/transitions/notecards.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/transitions/notecards.ts) + +```bash +node examples/transitions/sidebar.ts +node examples/transitions/notecards.ts +``` + +Change layout or style properties between frames and attach a [`transition`](/docs/tty/api/ops) to elements. Gate your render loop on [`animating`](/docs/tty/api/term) so you only redraw while motion is in progress. + +The sidebar demo animates width with keyboard shortcuts. Notecards interpolates layout and background color. + +{/* TODO: add transitions-sidebar.gif (record `node examples/transitions/sidebar.ts`) */} +{/* TODO: add transitions-notecards.gif (record `node examples/transitions/notecards.ts`) */} + +## Inline regions + +[`examples/inline-regions/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/inline-regions/index.ts) + +```bash +node examples/inline-regions/index.ts +``` + +Renders spinners, progress bars, and small animations into **normal scrollback** instead of taking over the screen. Uses [`DSR`](/docs/tty/api/termcodes) to query cursor position and [`render` in line mode](/docs/tty/api/term) to update a fixed region. + +Reach for this pattern when you want live output inside a regular CLI workflow (build logs, install progress, status lines) without switching to the alternate buffer. + +{/* TODO: add inline-regions.gif (record `node examples/inline-regions/index.ts`) */} + +## 2048 + +[`examples/2048/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/2048/index.ts) + +```bash +node examples/2048/index.ts +``` + +A complete game combining transitions, keyboard focus, pointer clicks, live resize, and an fps counter. Good reference once you understand the basics. + +**Controls:** arrows or `wasd` to move · `Tab`/`Shift+Tab` for focus · `Enter`/`Space` to activate · `n` new game · `u` undo · `q` or `Ctrl+C` to quit + +{/* TODO: add 2048.gif (record `node examples/2048/index.ts`) */} + +## Diff + +[`examples/diff/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/diff/index.ts) + +```bash +node examples/diff/index.ts +``` + +A code-review diff view with per-glyph `bg` highlighting on [`text`](/docs/tty/api/ops) nodes. Useful if you're building structured, read-only output rather than interactive UI. + +{/* TODO: add diff.gif (record `node examples/diff/index.ts`) */} + +## Next steps + +- [Getting Started](/docs/tty/basics/getting-started) (install, architecture, quick starts) +- [Term API](/docs/tty/api/term) (render loop and pointer events) +- [Input API](/docs/tty/api/input) (stdin event parsing) diff --git a/src/ec-themes.mjs b/src/ec-themes.mjs new file mode 100644 index 0000000..147560c --- /dev/null +++ b/src/ec-themes.mjs @@ -0,0 +1,136 @@ +// Monochrome Expressive Code themes: pure black & white, with hierarchy +// carried by grayscale dimming and font style instead of hue — code blocks +// read like the bomb.sh hero (white on black in a hairline frame). Terminal +// ANSI colors keep the brand palette so rendered terminal output still pops. +import { ExpressiveCodeTheme } from "@astrojs/starlight/expressive-code"; + +const palette = { + dark: { + bg: "#000000", + fg: "#f4f5f9", // --color-gray-20 + bright: "#ffffff", + string: "#a9abb6", // --color-gray-40 + punctuation: "#6c6e79", // --color-gray-60 + comment: "#484a54", // --color-gray-70 + selection: "#97979b33", + }, + light: { + bg: "#ffffff", + fg: "#191b23", // --color-gray-90 + bright: "#000000", + string: "#484a54", // --color-gray-70 + punctuation: "#8a8e9b", // --color-gray-50 + comment: "#a9abb6", // --color-gray-40 + selection: "#97979b33", + }, +}; + +function makeTheme(name, type, c) { + return new ExpressiveCodeTheme({ + name, + type, + colors: { + "editor.background": c.bg, + "editor.foreground": c.fg, + "editor.selectionBackground": c.selection, + "editorLineNumber.foreground": c.comment, + "terminal.ansiBlack": "#0a0a0d", + "terminal.ansiRed": "#ff3e47", + "terminal.ansiGreen": "#07f53f", + "terminal.ansiYellow": "#e8cf27", + "terminal.ansiBlue": "#054bff", + "terminal.ansiMagenta": "#ff00d2", + "terminal.ansiCyan": "#00e5ff", + "terminal.ansiWhite": "#ffffff", + }, + tokenColors: [ + { + scope: ["comment", "punctuation.definition.comment"], + settings: { foreground: c.comment, fontStyle: "italic" }, + }, + { + scope: [ + "punctuation", + "meta.brace", + "punctuation.definition.tag", + "keyword.operator", + ], + settings: { foreground: c.punctuation }, + }, + { + scope: [ + "keyword", + "storage.type", + "storage.modifier", + "keyword.control", + "entity.name.tag", + "punctuation.definition.keyword", + ], + settings: { foreground: c.bright, fontStyle: "bold" }, + }, + { + scope: [ + "string", + "string.template", + "punctuation.definition.string", + "markup.inline.raw", + ], + settings: { foreground: c.string }, + }, + { + scope: [ + "entity.name.function", + "support.function", + "meta.function-call entity.name.function", + "variable.function", + "entity.name.type", + "entity.name.class", + "support.type", + "support.class", + "entity.other.inherited-class", + "constant.numeric", + "constant.language", + "constant.character", + "constant.other", + "variable.other.constant", + "entity.other.attribute-name", + "support.type.property-name.json", + ], + settings: { foreground: c.bright }, + }, + { + scope: ["variable", "variable.parameter", "meta.object-literal.key"], + settings: { foreground: c.fg }, + }, + { + scope: [ + "string.regexp", + "constant.character.escape", + "punctuation.definition.template-expression", + ], + settings: { foreground: c.fg }, + }, + { + scope: ["invalid", "markup.deleted"], + settings: { foreground: c.punctuation }, + }, + { scope: ["markup.inserted"], settings: { foreground: c.bright } }, + { scope: ["markup.changed"], settings: { foreground: c.string } }, + { + scope: ["markup.heading", "entity.name.section"], + settings: { foreground: c.bright, fontStyle: "bold" }, + }, + { scope: ["markup.bold"], settings: { fontStyle: "bold" } }, + { scope: ["markup.italic"], settings: { fontStyle: "italic" } }, + { + scope: ["markup.underline.link", "string.other.link"], + settings: { foreground: c.fg, fontStyle: "underline" }, + }, + ], + }); +} + +export const ecThemes = [ + makeTheme("bombshell-dark", "dark", palette.dark), + makeTheme("bombshell-light", "light", palette.light), +]; diff --git a/src/starlightOverrides/Footer.astro b/src/starlightOverrides/Footer.astro new file mode 100644 index 0000000..55c8ed7 --- /dev/null +++ b/src/starlightOverrides/Footer.astro @@ -0,0 +1,100 @@ +--- +import Default from '@astrojs/starlight/components/Footer.astro'; +import { Icon } from '@astrojs/starlight/components'; +--- + + + + + diff --git a/src/starlightOverrides/Head.astro b/src/starlightOverrides/Head.astro index 8380aa0..f28424b 100644 --- a/src/starlightOverrides/Head.astro +++ b/src/starlightOverrides/Head.astro @@ -1,9 +1,34 @@ --- import Default from "@astrojs/starlight/components/Head.astro"; +import VtbotStarlight from "astro-vtbot/components/starlight/Base.astro"; +import "@fontsource-variable/inter"; import "/src/styles/starlight.css"; + +// Per-topic accent colors, matching the bomb.sh project cards +const ACCENTS = { + clack: { dark: "184 100% 48%", light: "184 100% 30%" }, + args: { dark: "52 100% 56%", light: "45 100% 33%" }, + tab: { dark: "142 100% 47%", light: "142 100% 28%" }, + tty: { dark: "300 100% 55%", light: "300 100% 38%" }, +}; +const accent = ACCENTS[Astro.locals.starlightRoute.id.split("/")[0]]; --- - +{/* replaceSidebarContent: sidebar content differs per topic (starlight-sidebar-topics) */} + + + +{ + accent && ( + + +{/* The site is dark-only, like bomb.sh: there is no theme switcher, and the + stored preference is pinned to dark (covering visitors who picked light + before the switcher was removed). This must run before Starlight's + ThemeProvider script (rendered later in ). */} + + + diff --git a/src/starlightOverrides/Header.astro b/src/starlightOverrides/Header.astro new file mode 100644 index 0000000..8238e26 --- /dev/null +++ b/src/starlightOverrides/Header.astro @@ -0,0 +1,115 @@ +--- +import Search from '@astrojs/starlight/components/Search.astro'; +import SocialIcons from '@astrojs/starlight/components/SocialIcons.astro'; +import SiteTitle from './SiteTitle.astro'; +--- + +
+
+ +
+
+ +
+
+ + +
+
+ + diff --git a/src/starlightOverrides/MarkdownContent.astro b/src/starlightOverrides/MarkdownContent.astro new file mode 100644 index 0000000..8fdb56c --- /dev/null +++ b/src/starlightOverrides/MarkdownContent.astro @@ -0,0 +1,10 @@ +--- +import "@astrojs/starlight/style/markdown.css"; +--- + +{/* Identical to Starlight's default MarkdownContent, plus the `content` class: + Starlight's TOC scrollspy observes `main .content > *`, but this site's + heading-wrapper markup leaves headings with no observable siblings, so + without this class `aria-current` only updates when a heading itself + crosses the intersection band and goes stale on jump-scrolls. */} +
diff --git a/src/starlightOverrides/MobileMenuFooter.astro b/src/starlightOverrides/MobileMenuFooter.astro new file mode 100644 index 0000000..1befb64 --- /dev/null +++ b/src/starlightOverrides/MobileMenuFooter.astro @@ -0,0 +1,30 @@ +--- +import SocialIcons from "@astrojs/starlight/components/SocialIcons.astro"; +--- + +{/* Like Starlight's default, minus the theme select — the site is dark-only. */} +
+ +
+ + diff --git a/src/starlightOverrides/SiteTitle.astro b/src/starlightOverrides/SiteTitle.astro new file mode 100644 index 0000000..cce6fa3 --- /dev/null +++ b/src/starlightOverrides/SiteTitle.astro @@ -0,0 +1,58 @@ +--- +--- + + + + + + + + + diff --git a/src/styles/asides.css b/src/styles/asides.css new file mode 100644 index 0000000..6acc648 --- /dev/null +++ b/src/styles/asides.css @@ -0,0 +1,268 @@ +/* Bombshell card asides. + Restyles Starlight's aside markup (`:::note` directives and the `