aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-09-01 14:48:45 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-09-01 14:48:45 +0300
commit8a6d697308162874a236c84aac0b0f8c7ac01f83 (patch)
treeed7dc7e8c6f50d66bde721fae78576aede929f66
parentb54a78aa510b87d1e3b56c619b72eaeb59e4a2a1 (diff)
refactor: separate website presentation from runtime
-rw-r--r--.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md4
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--.github/workflows/distribution.yml82
-rw-r--r--.github/workflows/preview.yml34
-rw-r--r--.github/workflows/release.yml46
-rw-r--r--.github/workflows/website-deploy.yml8
-rw-r--r--.github/workflows/website.yml54
-rw-r--r--.github/workflows/windows-arm64.yml4
-rw-r--r--.pi/prompts/pre-release-audit.md15
-rw-r--r--AGENTS.md16
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Cargo.toml2
-rw-r--r--distribution/agent-detection/amp.toml (renamed from website/agent-detection/amp.toml)0
-rw-r--r--distribution/agent-detection/antigravity.toml (renamed from website/agent-detection/antigravity.toml)0
-rw-r--r--distribution/agent-detection/claude.toml (renamed from website/agent-detection/claude.toml)0
-rw-r--r--distribution/agent-detection/cline.toml (renamed from website/agent-detection/cline.toml)0
-rw-r--r--distribution/agent-detection/codex.toml (renamed from website/agent-detection/codex.toml)0
-rw-r--r--distribution/agent-detection/cursor.toml (renamed from website/agent-detection/cursor.toml)0
-rw-r--r--distribution/agent-detection/devin.toml (renamed from website/agent-detection/devin.toml)0
-rw-r--r--distribution/agent-detection/droid.toml (renamed from website/agent-detection/droid.toml)0
-rw-r--r--distribution/agent-detection/gemini.toml (renamed from website/agent-detection/gemini.toml)0
-rw-r--r--distribution/agent-detection/github-copilot.toml (renamed from website/agent-detection/github-copilot.toml)0
-rw-r--r--distribution/agent-detection/grok.toml (renamed from website/agent-detection/grok.toml)0
-rw-r--r--distribution/agent-detection/hermes.toml (renamed from website/agent-detection/hermes.toml)0
-rw-r--r--distribution/agent-detection/index.toml (renamed from website/agent-detection/index.toml)0
-rw-r--r--distribution/agent-detection/kilo.toml (renamed from website/agent-detection/kilo.toml)0
-rw-r--r--distribution/agent-detection/kimi.toml (renamed from website/agent-detection/kimi.toml)0
-rw-r--r--distribution/agent-detection/kiro.toml (renamed from website/agent-detection/kiro.toml)0
-rw-r--r--distribution/agent-detection/maki.toml (renamed from website/agent-detection/maki.toml)0
-rw-r--r--distribution/agent-detection/opencode.toml (renamed from website/agent-detection/opencode.toml)0
-rw-r--r--distribution/agent-detection/pi.toml (renamed from website/agent-detection/pi.toml)0
-rw-r--r--distribution/agent-detection/qodercli.toml (renamed from website/agent-detection/qodercli.toml)0
-rw-r--r--distribution/agent-detection/qwen.toml (renamed from website/agent-detection/qwen.toml)0
-rw-r--r--distribution/agent-guide.md (renamed from website/agent-guide.md)0
-rw-r--r--distribution/install.cmd (renamed from website/install.cmd)0
-rw-r--r--distribution/install.ps1 (renamed from website/install.ps1)0
-rwxr-xr-xdistribution/install.sh (renamed from website/install.sh)0
-rw-r--r--distribution/latest.json (renamed from website/latest.json)0
-rw-r--r--distribution/preview.json (renamed from website/preview.json)0
-rw-r--r--docs/preview/README.md6
-rw-r--r--docs/versions/README.md7
-rw-r--r--justfile21
-rw-r--r--scripts/agent_detection_manifest_check.py75
-rw-r--r--scripts/changelog.py10
-rw-r--r--scripts/docs/preview.integration.test.ts (renamed from website/scripts/docs-preview.integration.test.ts)4
-rw-r--r--scripts/docs/preview.mjs (renamed from website/scripts/docs-preview.mjs)10
-rw-r--r--scripts/docs/snapshot.mjs (renamed from website/scripts/docs-snapshot.mjs)0
-rw-r--r--scripts/docs/versions.integration.test.ts (renamed from website/scripts/docs-versions.integration.test.ts)86
-rw-r--r--scripts/docs/versions.mjs (renamed from website/scripts/docs-versions.mjs)19
-rw-r--r--scripts/docs/versions.test.ts (renamed from website/scripts/docs-versions.test.ts)2
-rw-r--r--scripts/preview.py7
-rwxr-xr-xscripts/release_perf_smoke.sh2
-rw-r--r--scripts/test_agent_detection_manifest_check.py66
-rw-r--r--scripts/test_package_windows_conpty.py2
-rw-r--r--scripts/test_preview.py55
-rw-r--r--scripts/test_unix_installer.py2
-rw-r--r--scripts/windows_arm64_installer_test.ps12
-rw-r--r--scripts/windows_install_conpty_package_test.ps118
-rw-r--r--src/update.rs14
-rw-r--r--website/.gitignore9
-rw-r--r--website/README.md34
-rw-r--r--website/_headers52
-rw-r--r--website/_redirects4
-rw-r--r--website/assets/agent-icons/amp.svg1
-rw-r--r--website/assets/agent-icons/antigravity.svg1
-rw-r--r--website/assets/agent-icons/claude.svg1
-rw-r--r--website/assets/agent-icons/codex-mask.svg1
-rw-r--r--website/assets/agent-icons/codex.svg1
-rw-r--r--website/assets/agent-icons/cursor.svg1
-rw-r--r--website/assets/agent-icons/droid.pngbin43583 -> 0 bytes
-rw-r--r--website/assets/agent-icons/github-copilot.svg1
-rw-r--r--website/assets/agent-icons/grok.svg1
-rw-r--r--website/assets/agent-icons/herdr-mask.svg1
-rw-r--r--website/assets/agent-icons/hermes.svg1
-rw-r--r--website/assets/agent-icons/kimi.svg1
-rw-r--r--website/assets/agent-icons/kiro-mask.svg1
-rw-r--r--website/assets/agent-icons/kiro.svg11
-rw-r--r--website/assets/agent-icons/mastracode.svg3
-rw-r--r--website/assets/agent-icons/opencode.svg1
-rw-r--r--website/assets/agent-icons/pi.svg20
-rw-r--r--website/assets/agent-icons/qoder-mask.svg1
-rw-r--r--website/assets/author-can.jpegbin15326 -> 0 bytes
-rw-r--r--website/assets/favicon.pngbin7872 -> 0 bytes
-rw-r--r--website/assets/favicon.svg6
-rw-r--r--website/assets/jbm-OFL.txt93
-rw-r--r--website/assets/jbm.woff2bin30496 -> 0 bytes
-rw-r--r--website/assets/logo.pngbin120644 -> 0 bytes
-rw-r--r--website/assets/logo.svg6
-rw-r--r--website/assets/mobile-agent-session-v2.jpegbin150793 -> 0 bytes
-rw-r--r--website/assets/mobile-switch-menu-v2.jpegbin105386 -> 0 bytes
-rw-r--r--website/assets/og-blog-coding-agents-runtimes.pngbin279751 -> 0 bytes
-rw-r--r--website/assets/og-blog-frames-v1.pngbin62470 -> 0 bytes
-rw-r--r--website/assets/og-blog-live-updates.pngbin287024 -> 0 bytes
-rw-r--r--website/assets/og-blog-yc-v1.pngbin116338 -> 0 bytes
-rw-r--r--website/assets/og-card-v8.pngbin140428 -> 0 bytes
-rw-r--r--website/assets/og-card-v9.pngbin51248 -> 0 bytes
-rw-r--r--website/assets/ram.svg5
-rw-r--r--website/assets/releases/v0.6.3/session-navigator.mp4bin616072 -> 0 bytes
-rw-r--r--website/assets/where-do-agents-run-while-you-sleep.pngbin664934 -> 0 bytes
-rw-r--r--website/assets/yc-logo.svg7
-rw-r--r--website/astro.config.mjs251
-rw-r--r--website/bun.lock994
-rw-r--r--website/css/og-card.css102
-rw-r--r--website/css/site.css828
-rw-r--r--website/css/style.css3655
-rw-r--r--website/favicon.icobin15086 -> 0 bytes
-rw-r--r--website/index.html786
-rw-r--r--website/package.json20
-rw-r--r--website/robots.txt4
-rw-r--r--website/scripts/check-built-docs.mjs178
-rw-r--r--website/scripts/patch-starlight-llms.mjs54
-rw-r--r--website/scripts/prepare-docs.mjs479
-rw-r--r--website/src/components/AuthorCard.astro30
-rw-r--r--website/src/components/Banner.astro75
-rw-r--r--website/src/components/ConfigReference.astro204
-rw-r--r--website/src/components/DocsVersionSelect.astro84
-rw-r--r--website/src/components/Head.astro67
-rw-r--r--website/src/components/Header.astro99
-rw-r--r--website/src/components/MarketingLayout.astro274
-rw-r--r--website/src/components/Search.astro52
-rw-r--r--website/src/components/Sidebar.astro53
-rw-r--r--website/src/components/SiteLayout.astro223
-rw-r--r--website/src/components/SiteTitle.astro95
-rw-r--r--website/src/content.config.ts22
-rw-r--r--website/src/content/blog/coding-agents-are-becoming-runtimes.md166
-rw-r--r--website/src/content/blog/herdr-0-6-3.md85
-rw-r--r--website/src/content/blog/herdr-is-joining-y-combinator.md56
-rw-r--r--website/src/content/blog/live-updates-without-killing-your-terminal-processes.md125
-rw-r--r--website/src/content/blog/ten-agents-three-clients-95-percent-less-cpu.md157
-rw-r--r--website/src/data/plugins-fixture.json245
-rw-r--r--website/src/docs-path.test.ts63
-rw-r--r--website/src/docs-path.ts87
-rw-r--r--website/src/pages/blog/[slug].astro95
-rw-r--r--website/src/pages/blog/index.astro42
-rw-r--r--website/src/pages/compare.astro265
-rw-r--r--website/src/pages/index.astro33
-rw-r--r--website/src/pages/og/card-b.html60
-rw-r--r--website/src/pages/og/card-perf.html56
-rw-r--r--website/src/pages/og/card-yc.html42
-rw-r--r--website/src/pages/plugins.astro1159
-rw-r--r--website/src/site-data.ts103
-rw-r--r--website/src/styles/starlight.css273
142 files changed, 314 insertions, 12368 deletions
diff --git a/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md b/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md
index 0544b18e..2c90b4ce 100644
--- a/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md
+++ b/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md
@@ -75,13 +75,13 @@ Process:
- Audit `skills/herdr/SKILL.md` against shipped changes to the CLI, public IDs, pane and agent workflows, lifecycle semantics, and safety guidance. Flag stale commands, options, examples, or behavioral claims. The binary bundles this exact file, so review semantic freshness rather than file synchronization.
8. Verify finalization state.
- - Before `just release`, approved README changes must be finalized in `docs/next/README.md`; release CI promotes that tagged file after publication. Do not copy draft website docs into `website/src/content/docs/` or `docs/preview/`.
+ - Before `just release`, approved README changes must be finalized in `docs/next/README.md`; release CI promotes that tagged file after publication. Do not copy draft website docs into `docs/preview/` or `docs/versions/`.
- `nix/package.nix` imports `Cargo.lock` through `cargoLock.lockFile`; normal version and lockfile updates do not require a separate cargo hash refresh. If git dependencies are introduced, verify the required `cargoLock.outputHashes` entries.
- Run or recommend:
```bash
just pre-release-check
```
- - The docs check validates the staged draft, localized heading parity, published preview and stable snapshot provenance, and both production and draft website builds.
+ - The docs check validates the staged draft, localized heading parity, the public distribution contract, and published preview and stable snapshot provenance. The private website repository owns production and draft rendering checks.
- The render benchmark has no automatic timing threshold, but reviewing it is a required release checkpoint. Record the 1, 15, and 50-count median and p95 results for background-workspace resize/layout and active panes, compare their scaling ratios, and treat a material regression as a release blocker until investigated rather than relying on absolute timing across machines.
- Do not run `just release` unless the working tree is clean, the docs check passes, and the render-scale result has been reviewed.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 912ff332..fee229e5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,8 +5,6 @@ on:
types: [opened, synchronize, reopened]
push:
branches: [master, windows]
- paths-ignore:
- - "website/**"
permissions:
contents: read
diff --git a/.github/workflows/distribution.yml b/.github/workflows/distribution.yml
new file mode 100644
index 00000000..7062dc36
--- /dev/null
+++ b/.github/workflows/distribution.yml
@@ -0,0 +1,82 @@
+name: Distribution contract
+
+on:
+ pull_request:
+ paths:
+ - ".github/workflows/distribution.yml"
+ - "distribution/**"
+ - "docs/next/website/**"
+ - "docs/preview/**"
+ - "docs/versions/**"
+ - "scripts/agent_detection_manifest_check.py"
+ - "scripts/config_reference_check.py"
+ - "scripts/docs/**"
+ - "scripts/docs_translation_parity.py"
+ - "scripts/preview.py"
+ - "scripts/test_agent_detection_manifest_check.py"
+ - "scripts/test_config_reference_check.py"
+ - "scripts/test_docs_translation_parity.py"
+ - "scripts/test_preview.py"
+ - "src/detect/manifest_update.rs"
+ - "src/detect/manifests/**"
+ push:
+ branches: [master]
+ paths:
+ - ".github/workflows/distribution.yml"
+ - "distribution/**"
+ - "docs/next/website/**"
+ - "docs/preview/**"
+ - "docs/versions/**"
+ - "scripts/agent_detection_manifest_check.py"
+ - "scripts/config_reference_check.py"
+ - "scripts/docs/**"
+ - "scripts/docs_translation_parity.py"
+ - "scripts/preview.py"
+ - "scripts/test_agent_detection_manifest_check.py"
+ - "scripts/test_config_reference_check.py"
+ - "scripts/test_docs_translation_parity.py"
+ - "scripts/test_preview.py"
+ - "src/detect/manifest_update.rs"
+ - "src/detect/manifests/**"
+
+permissions:
+ contents: read
+
+concurrency:
+ group: distribution-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ validate:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - name: Checkout
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Install Bun
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
+ with:
+ bun-version: 1.3.14
+
+ - name: Test documentation lifecycle
+ run: bun test scripts/docs/*.test.ts
+
+ - name: Validate published contract
+ run: |
+ python3 scripts/agent_detection_manifest_check.py --require-published
+ python3 scripts/config_reference_check.py
+ python3 scripts/docs_translation_parity.py --docs-root docs/next/website/src/content/docs
+ node scripts/docs/versions.mjs check
+ node scripts/docs/preview.mjs check
+
+ - name: Test contract tooling
+ run: |
+ python3 -m unittest \
+ scripts.test_agent_detection_manifest_check \
+ scripts.test_config_reference_check \
+ scripts.test_docs_translation_parity \
+ scripts.test_preview
diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml
index f2314dcf..cd880016 100644
--- a/.github/workflows/preview.yml
+++ b/.github/workflows/preview.yml
@@ -57,8 +57,8 @@ jobs:
else
commit="$(python3 scripts/preview.py select-commit --ref origin/master)"
fi
- current_preview="$(python3 scripts/preview.py current-commit --manifest website/preview.json || true)"
- if [ "$current_preview" = "$commit" ] && node website/scripts/docs-preview.mjs check; then
+ current_preview="$(python3 scripts/preview.py current-commit --manifest distribution/preview.json || true)"
+ if [ "$current_preview" = "$commit" ] && node scripts/docs/preview.mjs check; then
echo "Preview and documentation already point at $commit; skipping."
echo "should_publish=false" >> "$GITHUB_OUTPUT"
exit 0
@@ -305,17 +305,12 @@ jobs:
with:
path: artifacts
- - name: Install Bun
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- with:
- bun-version: 1.3.14
-
- name: Record previous preview commit
id: previous-preview
shell: bash
run: |
set -euo pipefail
- previous="$(python3 scripts/preview.py current-commit --manifest website/preview.json || true)"
+ previous="$(python3 scripts/preview.py current-commit --manifest distribution/preview.json || true)"
if [ -z "$previous" ]; then
previous="$(git describe --tags --match 'v[0-9]*' --abbrev=0)"
fi
@@ -418,9 +413,9 @@ jobs:
- name: Update preview documentation and manifest
run: |
- node website/scripts/docs-preview.mjs snapshot '${{ needs.preflight.outputs.commit }}'
+ node scripts/docs/preview.mjs snapshot '${{ needs.preflight.outputs.commit }}'
python3 scripts/preview.py manifest \
- --output website/preview.json \
+ --output distribution/preview.json \
--tag '${{ needs.preflight.outputs.tag }}' \
--build-id '${{ needs.preflight.outputs.build_id }}' \
--commit '${{ needs.preflight.outputs.commit }}' \
@@ -430,7 +425,6 @@ jobs:
--notes PREVIEW_NOTES.md \
--sha-file preview-sha256.json \
--retain 30
- (cd website && bun install --frozen-lockfile)
- name: Commit preview publication
env:
@@ -438,14 +432,13 @@ jobs:
run: |
git config user.name "kangal-bot"
git config user.email "285672167+kangal-bot@users.noreply.github.com"
- git add -A docs/preview website/preview.json
+ git add -A docs/preview distribution/preview.json
git diff --cached --quiet || git commit -m "docs: publish preview documentation"
remote="https://x-access-token:${KANGAL_GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
for attempt in 1 2 3; do
git pull --rebase "$remote" master
- node website/scripts/docs-preview.mjs check
- node website/scripts/docs-versions.mjs check
- (cd website && bun run build)
+ node scripts/docs/preview.mjs check
+ node scripts/docs/versions.mjs check
if git push "$remote" HEAD:master; then
exit 0
fi
@@ -457,17 +450,6 @@ jobs:
echo "failed to publish preview documentation after 3 attempts" >&2
exit 1
- - name: Trigger website deploy
- env:
- DEPLOY_HOOK: ${{ secrets.CLOUDFLARE_PAGES_DEPLOY_HOOK }}
- run: |
- if [ -z "$DEPLOY_HOOK" ]; then
- echo "CLOUDFLARE_PAGES_DEPLOY_HOOK not set; relying on Cloudflare git auto-deploy"
- exit 0
- fi
- curl -fsS -X POST "$DEPLOY_HOOK" > /dev/null
- echo "Triggered Cloudflare Pages production deploy"
-
- name: Mark preview-released issues
continue-on-error: true
shell: bash
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index a7cc3558..3b835c7a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -191,6 +191,7 @@ jobs:
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
+ fetch-depth: 0
persist-credentials: false
- name: Install Bun
@@ -201,9 +202,13 @@ jobs:
- name: Validate release inputs
run: |
python3 scripts/changelog.py validate-product-announcement
+ python3 scripts/agent_detection_manifest_check.py --require-all-published
+ python3 scripts/config_reference_check.py
+ node scripts/docs/versions.mjs check
+ node scripts/docs/preview.mjs check
+ bun test scripts/docs/*.test.ts
test -f docs/next/README.md
test -f docs/next/README.zh-CN.md
- (cd website && bun install --frozen-lockfile && bun run test && bun run build:draft)
release:
needs: [build, flake-check, validate-release-inputs]
@@ -388,17 +393,12 @@ jobs:
fetch-depth: 0
ssh-key: ${{ secrets.RELEASE_DEPLOY_KEY }}
- - name: Install Bun
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- with:
- bun-version: 1.3.14
-
- - name: Publish tagged documentation and update website manifest
+ - name: Publish tagged documentation and update distribution manifest
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="${GITHUB_REF_NAME#v}"
- node website/scripts/docs-versions.mjs publish "$GITHUB_REF_NAME"
+ node scripts/docs/versions.mjs publish "$GITHUB_REF_NAME"
ANNOUNCEMENT_PATH="$RUNNER_TEMP/product-announcement.json"
ANNOUNCEMENT_ORIGINAL_PATH="$RUNNER_TEMP/product-announcement-original.json"
git show "${GITHUB_REF_NAME}:docs/next/product-announcement.json" > "$ANNOUNCEMENT_PATH"
@@ -406,35 +406,34 @@ jobs:
python3 scripts/changelog.py validate-product-announcement --path "$ANNOUNCEMENT_PATH"
RELEASE_PROTOCOL=$(git show "${GITHUB_REF_NAME}:src/protocol/wire.rs" | python3 -c 'import re, sys; match = re.search(r"pub const PROTOCOL_VERSION: u32 = (\d+);", sys.stdin.read()); sys.exit(1) if match is None else print(match.group(1))')
- DOCS_CURRENT=$(node website/scripts/docs-versions.mjs current)
+ DOCS_CURRENT=$(node scripts/docs/versions.mjs current)
if [ "$DOCS_CURRENT" != "$VERSION" ]; then
echo "Archived v$VERSION documentation without moving current docs backward from v$DOCS_CURRENT"
exit 0
fi
- CURRENT_VERSION=$(python3 -c 'import json; print(json.load(open("website/latest.json")).get("version", ""))')
+ CURRENT_VERSION=$(python3 -c 'import json; print(json.load(open("distribution/latest.json")).get("version", ""))')
if [ "$CURRENT_VERSION" = "$VERSION" ]; then
- echo "website/latest.json is already at v$VERSION"
+ echo "distribution/latest.json is already at v$VERSION"
exit 0
fi
- python3 scripts/changelog.py sync-latest-json --version "$VERSION" --output website/latest.json --announcement "$ANNOUNCEMENT_PATH" --protocol "$RELEASE_PROTOCOL"
+ python3 scripts/changelog.py sync-latest-json --version "$VERSION" --output distribution/latest.json --announcement "$ANNOUNCEMENT_PATH" --protocol "$RELEASE_PROTOCOL"
if cmp -s "$ANNOUNCEMENT_ORIGINAL_PATH" docs/next/product-announcement.json; then
printf 'null\n' > docs/next/product-announcement.json
else
echo "::warning::docs/next/product-announcement.json changed after $GITHUB_REF_NAME; leaving it unchanged."
fi
- - name: Commit website latest manifest
+ - name: Commit release distribution
run: |
VERSION="${GITHUB_REF_NAME#v}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git add -A README.md README.zh-CN.md docs/versions website/latest.json docs/next/product-announcement.json
- git diff --cached --quiet || git commit -m "docs: update website manifest for v$VERSION"
+ git add -A README.md README.zh-CN.md docs/versions distribution/latest.json docs/next/product-announcement.json
+ git diff --cached --quiet || git commit -m "docs: publish release distribution for v$VERSION"
for attempt in 1 2 3; do
git pull --rebase origin master
- node website/scripts/docs-versions.mjs check
- node website/scripts/docs-preview.mjs check
- (cd website && bun install --frozen-lockfile && bun run build)
+ node scripts/docs/versions.mjs check
+ node scripts/docs/preview.mjs check
if git push origin master; then
exit 0
fi
@@ -445,14 +444,3 @@ jobs:
done
echo "failed to publish release documentation after 3 attempts" >&2
exit 1
-
- - name: Trigger website deploy
- env:
- DEPLOY_HOOK: ${{ secrets.CLOUDFLARE_PAGES_DEPLOY_HOOK }}
- run: |
- if [ -z "$DEPLOY_HOOK" ]; then
- echo "CLOUDFLARE_PAGES_DEPLOY_HOOK not set; relying on Cloudflare git auto-deploy"
- exit 0
- fi
- curl -fsS -X POST "$DEPLOY_HOOK" > /dev/null
- echo "Triggered Cloudflare Pages production deploy"
diff --git a/.github/workflows/website-deploy.yml b/.github/workflows/website-deploy.yml
index 7220af72..88283d6e 100644
--- a/.github/workflows/website-deploy.yml
+++ b/.github/workflows/website-deploy.yml
@@ -9,13 +9,7 @@ on:
- "docs/preview/**"
- "docs/versions/**"
- "src/detect/manifests/**"
- - "website/agent-detection/**"
- - "website/agent-guide.md"
- - "website/install.cmd"
- - "website/install.ps1"
- - "website/install.sh"
- - "website/latest.json"
- - "website/preview.json"
+ - "distribution/**"
permissions:
contents: read
diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
deleted file mode 100644
index b437c61f..00000000
--- a/.github/workflows/website.yml
+++ /dev/null
@@ -1,54 +0,0 @@
-name: Website
-
-on:
- pull_request:
- paths:
- - ".github/workflows/website.yml"
- - "website/**"
- - "docs/next/website/**"
- - "docs/preview/**"
- - "docs/versions/**"
- - "scripts/test_preview.py"
- push:
- branches: [master]
- paths:
- - ".github/workflows/website.yml"
- - "website/**"
- - "docs/next/website/**"
- - "docs/preview/**"
- - "docs/versions/**"
- - "scripts/test_preview.py"
-
-permissions:
- contents: read
-
-concurrency:
- group: website-${{ github.event.pull_request.number || github.ref }}
- cancel-in-progress: true
-
-jobs:
- build:
- runs-on: ubuntu-latest
- timeout-minutes: 10
- steps:
- - name: Checkout
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- with:
- fetch-depth: 0
- persist-credentials: false
-
- - name: Install Bun
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- with:
- bun-version: 1.3.14
-
- - name: Validate published documentation
- run: |
- node website/scripts/docs-versions.mjs check
- node website/scripts/docs-preview.mjs check
-
- - name: Build published website
- run: cd website && bun install --frozen-lockfile && bun run build
-
- - name: Validate unpublished draft
- run: cd website && bun run build:draft
diff --git a/.github/workflows/windows-arm64.yml b/.github/workflows/windows-arm64.yml
index 1488d1f1..9904281b 100644
--- a/.github/workflows/windows-arm64.yml
+++ b/.github/workflows/windows-arm64.yml
@@ -6,13 +6,13 @@ on:
paths:
- ".github/workflows/windows-arm64.yml"
- "scripts/windows_arm64_installer_test.ps1"
- - "website/install.ps1"
+ - "distribution/install.ps1"
push:
branches: [master]
paths:
- ".github/workflows/windows-arm64.yml"
- "scripts/windows_arm64_installer_test.ps1"
- - "website/install.ps1"
+ - "distribution/install.ps1"
permissions:
contents: read
diff --git a/.pi/prompts/pre-release-audit.md b/.pi/prompts/pre-release-audit.md
index 3e851d54..c0e53783 100644
--- a/.pi/prompts/pre-release-audit.md
+++ b/.pi/prompts/pre-release-audit.md
@@ -61,27 +61,28 @@ Process:
- Preserve the existing changelog style and sections: `Added`, `Changed`, `Fixed`, `Removed`, and `Breaking Changes` when applicable.
7. Audit next-release public docs.
- - Treat root `README.md` and `website/src/content/docs/` as the latest released public docs.
- - Treat `docs/next/README.md` as the next-release root README, and `docs/next/website/src/content/docs/` as the full next-release mirror of website docs.
+ - Treat root `README.md` and the version selected by `docs/versions/manifest.json` under `docs/versions/<current>/website/src/content/docs/` as the latest released public docs.
+ - Treat `docs/next/README.md` as the next-release root README and `docs/next/website/src/content/docs/` as the complete unpublished website-doc draft.
+ - Treat `docs/preview/website/` as bot-owned output for the active preview release. Never edit it during release review.
- Compare meaningful user-facing changes in the range against next-release docs first.
- Flag missing release docs for new or changed features, commands, config keys, protocol behavior, integrations, defaults, and compatibility notes.
- - Compare `docs/next/README.md` against root `README.md`, and compare the staged website-doc mirror against `website/src/content/docs/`. Flag each difference as intended to ship in this release, stale, or needing user decision.
+ - Compare `docs/next/README.md` and the next website draft against current stable docs. Flag each difference as intended to ship, stale, or needing user decision.
- Also audit example config snippets for release readiness.
8. Verify finalization state.
- - Before `just release`, approved `docs/next/README.md` must be copied to root `README.md`, approved staged website docs must be copied from `docs/next/website/src/content/docs/` to `website/src/content/docs/`, and the deleted root doc files must stay deleted.
- - If the release will change `Cargo.lock` or the package version, check `nix/package.nix` after the release version bump and refresh `cargoHash` before tagging. A stale hash fails both the `Nix` workflow and the release workflow's `flake-check` job with a fixed-output derivation mismatch. Use the `got:` hash printed by `nix flake check --print-build-logs` or CI, then rerun the Nix check when available.
+ - Before `just release`, approved README changes must be finalized in `docs/next/README.md`; release CI promotes that tagged file after publication. Do not copy draft website docs into `docs/preview/` or `docs/versions/`.
+ - `nix/package.nix` imports `Cargo.lock` through `cargoLock.lockFile`; normal version and lockfile updates do not require a separate cargo hash refresh.
- Run or recommend:
```bash
just release-docs-check
```
- - This check must include root `README.md`, root `CHANGELOG.md`, the removed root doc files, and exact 1:1 sync between `docs/next/website/src/content/docs/` and `website/src/content/docs/`.
+ - The docs check validates the staged draft, the public distribution contract, and published preview and stable snapshot provenance. The private website repository owns rendering checks.
- Do not run `just release` unless the working tree is clean and the docs check passes.
9. Apply changes only when asked.
- Do not edit files during the audit unless the user explicitly asks you to apply fixes.
- When asked to apply audit fixes, update `docs/next/CHANGELOG.md`, `docs/next/README.md`, and any required staged website docs under `docs/next/website/src/content/docs/`.
- - When asked to finalize release docs, copy approved next-release README and changelog into root, copy approved staged website docs into `website/src/content/docs/`, then run `just release-docs-check`.
+ - When asked to finalize release docs, finalize only the staged files under `docs/next/`, then run `just release-docs-check`. Preview and stable publication remain CI-owned.
Output format:
diff --git a/AGENTS.md b/AGENTS.md
index 72755f89..685d7078 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -175,6 +175,8 @@ Agent detection changes should use the manifest hot-reload loop. Use the project
Do not add large agent-specific full-screen fixture suites for routine manifest tuning. Keep Rust tests focused on manifest parsing, rule semantics, skip-state semantics, source precedence, cache reload behavior, and update flow. Use live pane reads for agent-specific screen evidence.
+`distribution/agent-detection/` is the remotely published catalog for released clients. Keep changes for already released agents aligned with their bundled manifests unless the validator records an exact compatibility exception. A newly bundled agent that current stable clients cannot identify may remain unpublished behind an exact version-and-digest exception, but it must be added to the catalog and the exception removed before the first stable release that ships it. `just release-docs-check` enforces that no unpublished exceptions remain.
+
## Vendored libghostty-vt
`vendor/libghostty-vt.vendor.json` records the upstream source commit currently vendored.
@@ -191,15 +193,15 @@ When updating libghostty-vt, check every active patch in `vendor/libghostty-vt.p
Unreleased docs live in `docs/next/website/src/content/docs/`. Update those when a user-facing change needs docs before the next release. They are committed drafts but are never production website input. `docs/next/README.md` stages root README changes. `docs/next/CHANGELOG.md` is curated during stable release preparation, not maintained by normal feature and fix work.
-The active preview release docs live in `docs/preview/website/`. Preview CI owns this mutable snapshot and commits it atomically with `website/preview.json`; never edit it manually. Validate it with `node website/scripts/docs-preview.mjs check`.
+The active preview release docs live in `docs/preview/website/`. Preview CI owns this mutable snapshot and commits it atomically with `distribution/preview.json`; never edit it manually. Validate it with `node scripts/docs/preview.mjs check`.
-Published stable-release documentation lives in `docs/versions/`. Release CI seeds each version from the tagged `docs/next` tree, and maintainers may correct factual documentation errors in a published version afterward. Apply a correction separately to `docs/next` when it also applies to future releases; never replace a published tree with the current draft. The website build generates `/docs/preview/` from the active preview snapshot, `/docs/<version>/` from the maintained version directories, and `/docs/` from the version selected by `docs/versions/manifest.json`. Do not edit generated files under `website/src/content/docs/`.
+Published stable-release documentation lives in `docs/versions/`. Release CI seeds each version from the tagged `docs/next` tree, and maintainers may correct factual documentation errors in a published version afterward. Apply a correction separately to `docs/next` when it also applies to future releases; never replace a published tree with the current draft. The private website renders `/docs/preview/` from the active preview snapshot, `/docs/<version>/` from the maintained version directories, and `/docs/` from the version selected by `docs/versions/manifest.json`. Herdr remains the source of truth for the public snapshots.
-During release review, finalize `docs/next` and run `just release-docs-check`. Do not copy draft docs into preview or published versions manually. Preview CI snapshots the selected commit. After a stable GitHub Release succeeds, release CI seeds a new version from the exact tag, updates `latest.json`, and deploys them together.
+During release review, finalize `docs/next` and run `just release-docs-check`. Do not copy draft docs into preview or published versions manually. Preview CI snapshots the selected commit. After a stable GitHub Release succeeds, release CI seeds a new version from the exact tag and updates `distribution/latest.json`. The resulting master commit triggers the private website deployment.
Normal feature and fix work must not edit `docs/next/CHANGELOG.md`; this keeps long-lived branches from conflicting over one shared release file. When refreshing an older pull request, remove its changelog-only diff. Keep user-facing commit subjects descriptive and include required `refs #<issue-number>` lines so stable release preparation can inventory the full range. During the pre-release audit, use that inventory to human-write and curate the user-facing entries in `docs/next/CHANGELOG.md`; generated commit lists are source material, not final release prose. Do not add changelog entries for website-only, documentation-only, CI, build-pipeline, or repository-maintenance changes.
-Normal feature/fix work should not edit root `README.md`, root `CHANGELOG.md`, published version docs, or `website/latest.json` unless it is a focused correction to already-published documentation or explicitly requested.
+Normal feature/fix work should not edit root `README.md`, root `CHANGELOG.md`, published version docs, or `distribution/latest.json` unless it is a focused correction to already-published documentation or explicitly requested.
Put local PRDs, planning notes, and exploratory specs under `.local/prd/`; `.local/` is ignored and locally controlled.
@@ -236,7 +238,7 @@ guardrail.
Herdr has one main branch and two update channels. Stable and preview both build from `master`; there is no long-lived preview branch.
-Normal users default to stable. Stable docs are `/docs/`, stable updates use `website/latest.json`, and Homebrew/Nix stay stable-only.
+Normal users default to stable. Stable docs are `/docs/`, stable updates use `distribution/latest.json`, and Homebrew/Nix stay stable-only.
Preview is opt-in for direct Herdr installs:
@@ -252,7 +254,7 @@ herdr channel set stable
herdr update
```
-Preview releases are GitHub prereleases produced by `.github/workflows/preview.yml` on manual dispatch and the Wednesday/Friday schedule. The workflow updates `website/preview.json`, which the website build publishes as `/preview.json`. Do not hand-edit `website/preview.json`; fix the workflow or `scripts/preview.py` and rerun Preview.
+Preview releases are GitHub prereleases produced by `.github/workflows/preview.yml` on manual dispatch and the Wednesday/Friday schedule. The workflow updates `distribution/preview.json`, which the private website publishes as `/preview.json`. Do not hand-edit `distribution/preview.json`; fix the workflow or `scripts/preview.py` and rerun Preview.
Stable releases use:
@@ -261,7 +263,7 @@ just check
just release 0.x.y
```
-Before stable release, run `/pre-release-audit`, finalize `docs/next`, and run `just pre-release-check` to validate the staged docs, website build, and render scaling. `just release` prepares the changelog and release commit, tags it, and pushes the tag. GitHub Actions builds binaries, creates the GitHub release, closes released issues, snapshots and promotes the tagged docs, and updates `website/latest.json`.
+Before stable release, run `/pre-release-audit`, finalize `docs/next`, and run `just pre-release-check` to validate the staged docs, distribution contract, and render scaling. `just release` prepares the changelog and release commit, tags it, and pushes the tag. GitHub Actions builds binaries, creates the GitHub release, closes released issues, snapshots and promotes the tagged docs, and updates `distribution/latest.json`. The private website repository owns rendering and deployment.
Before the first stable Windows release, publish and verify a preview containing stable-channel support. Existing Windows preview users need that preview before `herdr channel set stable` can migrate them.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 93e8b9c2..cc772265 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -121,7 +121,7 @@ The checks must pass. Make sure the tests exercise the reported failure and woul
### Handle documentation correctly
-For normal code changes, do not edit the root `README.md`, root `CHANGELOG.md`, `docs/preview/`, `docs/versions/`, or generated files under `website/src/content/docs/`.
+For normal code changes, do not edit the root `README.md`, root `CHANGELOG.md`, `docs/preview/`, `docs/versions/`, or release payloads under `distribution/`.
When a user-facing change needs documentation, update the unreleased draft under `docs/next/` or explain what documentation will be needed. Maintainers prepare the next changelog during release review.
diff --git a/Cargo.toml b/Cargo.toml
index 55ee3d03..02edde19 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,7 +14,7 @@ include = [
"assets/sounds/*",
"docs/next/api/herdr-api.schema.json",
"skills/herdr/SKILL.md",
- "website/install.ps1",
+ "distribution/install.ps1",
"README.md",
"LICENSE",
"Cargo.toml",
diff --git a/website/agent-detection/amp.toml b/distribution/agent-detection/amp.toml
index 1fc5dfa6..1fc5dfa6 100644
--- a/website/agent-detection/amp.toml
+++ b/distribution/agent-detection/amp.toml
diff --git a/website/agent-detection/antigravity.toml b/distribution/agent-detection/antigravity.toml
index 8b9bcfcf..8b9bcfcf 100644
--- a/website/agent-detection/antigravity.toml
+++ b/distribution/agent-detection/antigravity.toml
diff --git a/website/agent-detection/claude.toml b/distribution/agent-detection/claude.toml
index 55adacd6..55adacd6 100644
--- a/website/agent-detection/claude.toml
+++ b/distribution/agent-detection/claude.toml
diff --git a/website/agent-detection/cline.toml b/distribution/agent-detection/cline.toml
index b30f4417..b30f4417 100644
--- a/website/agent-detection/cline.toml
+++ b/distribution/agent-detection/cline.toml
diff --git a/website/agent-detection/codex.toml b/distribution/agent-detection/codex.toml
index 6833f390..6833f390 100644
--- a/website/agent-detection/codex.toml
+++ b/distribution/agent-detection/codex.toml
diff --git a/website/agent-detection/cursor.toml b/distribution/agent-detection/cursor.toml
index ee03e6db..ee03e6db 100644
--- a/website/agent-detection/cursor.toml
+++ b/distribution/agent-detection/cursor.toml
diff --git a/website/agent-detection/devin.toml b/distribution/agent-detection/devin.toml
index c9564f7c..c9564f7c 100644
--- a/website/agent-detection/devin.toml
+++ b/distribution/agent-detection/devin.toml
diff --git a/website/agent-detection/droid.toml b/distribution/agent-detection/droid.toml
index c41d71b4..c41d71b4 100644
--- a/website/agent-detection/droid.toml
+++ b/distribution/agent-detection/droid.toml
diff --git a/website/agent-detection/gemini.toml b/distribution/agent-detection/gemini.toml
index 9d7a28e1..9d7a28e1 100644
--- a/website/agent-detection/gemini.toml
+++ b/distribution/agent-detection/gemini.toml
diff --git a/website/agent-detection/github-copilot.toml b/distribution/agent-detection/github-copilot.toml
index 57fafdd8..57fafdd8 100644
--- a/website/agent-detection/github-copilot.toml
+++ b/distribution/agent-detection/github-copilot.toml
diff --git a/website/agent-detection/grok.toml b/distribution/agent-detection/grok.toml
index 996cf377..996cf377 100644
--- a/website/agent-detection/grok.toml
+++ b/distribution/agent-detection/grok.toml
diff --git a/website/agent-detection/hermes.toml b/distribution/agent-detection/hermes.toml
index 17542184..17542184 100644
--- a/website/agent-detection/hermes.toml
+++ b/distribution/agent-detection/hermes.toml
diff --git a/website/agent-detection/index.toml b/distribution/agent-detection/index.toml
index f44a8306..f44a8306 100644
--- a/website/agent-detection/index.toml
+++ b/distribution/agent-detection/index.toml
diff --git a/website/agent-detection/kilo.toml b/distribution/agent-detection/kilo.toml
index 4ef004e1..4ef004e1 100644
--- a/website/agent-detection/kilo.toml
+++ b/distribution/agent-detection/kilo.toml
diff --git a/website/agent-detection/kimi.toml b/distribution/agent-detection/kimi.toml
index b4d0100f..b4d0100f 100644
--- a/website/agent-detection/kimi.toml
+++ b/distribution/agent-detection/kimi.toml
diff --git a/website/agent-detection/kiro.toml b/distribution/agent-detection/kiro.toml
index 59ac0a06..59ac0a06 100644
--- a/website/agent-detection/kiro.toml
+++ b/distribution/agent-detection/kiro.toml
diff --git a/website/agent-detection/maki.toml b/distribution/agent-detection/maki.toml
index 5c58404a..5c58404a 100644
--- a/website/agent-detection/maki.toml
+++ b/distribution/agent-detection/maki.toml
diff --git a/website/agent-detection/opencode.toml b/distribution/agent-detection/opencode.toml
index 52452383..52452383 100644
--- a/website/agent-detection/opencode.toml
+++ b/distribution/agent-detection/opencode.toml
diff --git a/website/agent-detection/pi.toml b/distribution/agent-detection/pi.toml
index a58d30e9..a58d30e9 100644
--- a/website/agent-detection/pi.toml
+++ b/distribution/agent-detection/pi.toml
diff --git a/website/agent-detection/qodercli.toml b/distribution/agent-detection/qodercli.toml
index 51ca805e..51ca805e 100644
--- a/website/agent-detection/qodercli.toml
+++ b/distribution/agent-detection/qodercli.toml
diff --git a/website/agent-detection/qwen.toml b/distribution/agent-detection/qwen.toml
index bbed2371..bbed2371 100644
--- a/website/agent-detection/qwen.toml
+++ b/distribution/agent-detection/qwen.toml
diff --git a/website/agent-guide.md b/distribution/agent-guide.md
index b542dd94..b542dd94 100644
--- a/website/agent-guide.md
+++ b/distribution/agent-guide.md
diff --git a/website/install.cmd b/distribution/install.cmd
index 325e3b38..325e3b38 100644
--- a/website/install.cmd
+++ b/distribution/install.cmd
diff --git a/website/install.ps1 b/distribution/install.ps1
index 94a57314..94a57314 100644
--- a/website/install.ps1
+++ b/distribution/install.ps1
diff --git a/website/install.sh b/distribution/install.sh
index 4e3ce40d..4e3ce40d 100755
--- a/website/install.sh
+++ b/distribution/install.sh
diff --git a/website/latest.json b/distribution/latest.json
index a0ffe777..a0ffe777 100644
--- a/website/latest.json
+++ b/distribution/latest.json
diff --git a/website/preview.json b/distribution/preview.json
index 806852e6..806852e6 100644
--- a/website/preview.json
+++ b/distribution/preview.json
diff --git a/docs/preview/README.md b/docs/preview/README.md
index f8ba2c6a..bd7c4bce 100644
--- a/docs/preview/README.md
+++ b/docs/preview/README.md
@@ -1,9 +1,9 @@
# Preview documentation
-`website/` is the committed documentation snapshot for the active preview release in `website/preview.json`.
+`website/` is the committed documentation snapshot for the active preview release recorded in `distribution/preview.json`.
-Do not edit it manually. Preview CI replaces it from the selected commit's `docs/next/website` tree and commits the snapshot together with `website/preview.json`. Validate it with:
+Do not edit it manually. Preview CI replaces it from the selected commit's `docs/next/website` tree and commits the snapshot together with `distribution/preview.json`. Validate it with:
```bash
-node website/scripts/docs-preview.mjs check
+node scripts/docs/preview.mjs check
```
diff --git a/docs/versions/README.md b/docs/versions/README.md
index 42ca1c69..502d1d43 100644
--- a/docs/versions/README.md
+++ b/docs/versions/README.md
@@ -4,14 +4,13 @@ This directory contains the published documentation for stable Herdr releases.
Release CI creates each version from the tagged `docs/next` tree after the GitHub Release succeeds. Maintainers can correct published documentation in its version directory afterward. When a correction also applies to future releases, make the same focused change under `docs/next`; do not replace a published tree with the current draft.
-Validate the manifest and build every published version with:
+Validate every published version with:
```bash
-node website/scripts/docs-versions.mjs check
-cd website && bun run build
+node scripts/docs/versions.mjs check
```
-`website/scripts/prepare-docs.mjs` renders each maintained version at `/docs/<version>/` and uses the version selected by `manifest.json` for `/docs/`. Generated files under `website/src/content/docs/` are not editable sources. `/docs/preview/` comes only from the active preview release snapshot in `docs/preview/`, never directly from `docs/next/`.
+The private website renders each maintained version at `/docs/<version>/`, uses the version selected by `manifest.json` for `/docs/`, and renders the active preview snapshot at `/docs/preview/`. The source snapshots in this directory remain public release evidence; the private repository owns only their presentation.
The `tag`, `commit`, and `source` fields in `manifest.json` record where release CI initially published a version. Git history records later documentation corrections.
diff --git a/justfile b/justfile
index fe195a32..1ea382e5 100644
--- a/justfile
+++ b/justfile
@@ -7,6 +7,7 @@ test:
just ui-hot-path-architecture-test
just integration-assets-test
just plugin-marketplace-test
+ just docs-contract-test
# Run one nextest filter, e.g. `just test-one codex_stale_working`
[unix]
@@ -51,6 +52,7 @@ windows-lint:
[unix]
check: ci windows-lint
python3 -m unittest scripts.test_agent_detection_manifest_check scripts.test_changelog scripts.test_config_reference_check scripts.test_docs_translation_parity scripts.test_hermes_integration_asset scripts.test_package_windows_conpty scripts.test_preview scripts.test_unix_installer scripts.test_vendor_libghostty_vt scripts.test_vendor_portable_pty
+ just docs-contract-test
@echo "docs reminder: if this changes user-facing behavior, make sure the relevant release docs are updated or called out before release."
[script("powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File")]
@@ -84,9 +86,9 @@ bench-release-smoke:
cargo build --release --locked
scripts/release_perf_smoke.sh "${CARGO_TARGET_DIR:-target}/release/herdr"
-# Build the website and documentation
-website-build:
- cd website && bun install --frozen-lockfile && bun run build
+# Test public documentation snapshot and release lifecycle tooling
+docs-contract-test:
+ bun test scripts/docs/*.test.ts
# Test bundled agent integration assets
integration-assets-test:
@@ -104,10 +106,11 @@ build-libghostty-vt:
# Check that release docs and changelog have been finalized from docs/next before release
release-docs-check:
- python3 scripts/agent_detection_manifest_check.py --require-website
+ python3 scripts/agent_detection_manifest_check.py --require-all-published
python3 scripts/config_reference_check.py
- node website/scripts/docs-versions.mjs check
- node website/scripts/docs-preview.mjs check
+ node scripts/docs/versions.mjs check
+ node scripts/docs/preview.mjs check
+ just docs-contract-test
@test -f docs/next/README.md
@test -f docs/next/README.zh-CN.md
@if ! diff -u CHANGELOG.md docs/next/CHANGELOG.md; then \
@@ -116,7 +119,7 @@ release-docs-check:
fi
@for file in CONFIGURATION.md INTEGRATIONS.md SOCKET_API.md; do \
if [ -e "$file" ]; then \
- echo "error: $file was replaced by website docs; remove the root copy"; \
+ echo "error: $file was replaced by technical docs; remove the root copy"; \
exit 1; \
fi; \
done
@@ -138,8 +141,6 @@ release-docs-check:
fi; \
done
python3 scripts/docs_translation_parity.py --docs-root docs/next/website/src/content/docs
- just website-build
- cd website && bun run build:draft
# Validate release docs, render scaling, and end-to-end CPU before release preparation
pre-release-check:
@@ -217,7 +218,7 @@ release-publish version:
fi
git tag -a v{{version}} -m "v{{version}}"
git push origin v{{version}}
- @echo "v{{version}} released — GitHub Actions building binaries and updating website/latest.json"
+ @echo "v{{version}} released — GitHub Actions building binaries and updating distribution/latest.json"
# Prepare, verify, tag, push, and trigger the GitHub Release workflow (usage: just release 0.1.1)
release version:
diff --git a/scripts/agent_detection_manifest_check.py b/scripts/agent_detection_manifest_check.py
index f180318b..f0dc0005 100644
--- a/scripts/agent_detection_manifest_check.py
+++ b/scripts/agent_detection_manifest_check.py
@@ -13,7 +13,7 @@ from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
DEFAULT_BUNDLED_DIR = PROJECT_ROOT / "src" / "detect" / "manifests"
-DEFAULT_WEBSITE_DIR = PROJECT_ROOT / "website" / "agent-detection"
+DEFAULT_PUBLISHED_DIR = PROJECT_ROOT / "distribution" / "agent-detection"
ENGINE_SOURCE = PROJECT_ROOT / "src" / "detect" / "manifest_update.rs"
MANIFEST_KEYS = {"id", "version", "min_engine_version", "updated_at", "aliases", "rules"}
@@ -54,9 +54,9 @@ MAX_TOTAL_MATCHERS = 1024
MAX_MATCHER_CHARS = 512
# Keep engine-2 clients on the OSC-capable manifest until an engine-3 release
-# can consume top_non_empty_lines. Remove this entry when the website publishes
-# the bundled Grok manifest.
-STAGED_WEBSITE_MANIFESTS = {
+# can consume top_non_empty_lines. Remove this entry when the distribution
+# publishes the bundled Grok manifest.
+STAGED_PUBLISHED_MANIFESTS = {
"grok": (
"2026.07.16.2",
"2026.07.16.1",
@@ -64,16 +64,31 @@ STAGED_WEBSITE_MANIFESTS = {
),
}
+# Muse is bundled on master but has not shipped in a stable binary yet. Stable
+# clients cannot identify it, so publish it with the release that first ships
+# the corresponding Agent variant and remove this exact-content exception.
+UNPUBLISHED_BUNDLED_MANIFESTS = {
+ "muse": (
+ "2026.08.26.1",
+ "b69c4d87fa9c19e3e6453b706fbe39c98a8b33ffbaa48e8cd5ae6751e9615074",
+ ),
+}
+
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--bundled-dir", type=Path, default=DEFAULT_BUNDLED_DIR)
- parser.add_argument("--website-dir", type=Path, default=DEFAULT_WEBSITE_DIR)
+ parser.add_argument("--published-dir", type=Path, default=DEFAULT_PUBLISHED_DIR)
parser.add_argument("--engine-version", type=int)
parser.add_argument(
- "--require-website",
+ "--require-published",
+ action="store_true",
+ help="fail if published agent-detection assets or catalog are missing",
+ )
+ parser.add_argument(
+ "--require-all-published",
action="store_true",
- help="fail if website agent-detection assets or catalog are missing",
+ help="fail if any bundled manifest is intentionally held for a future stable release",
)
return parser.parse_args()
@@ -286,11 +301,13 @@ def load_manifest_dir(path: Path, engine_version: int) -> dict[str, tuple[Path,
def validate_catalog(
- website_dir: Path,
+ published_dir: Path,
bundled: dict[str, tuple[Path, dict]],
engine_version: int,
+ *,
+ allow_unpublished: bool = False,
) -> None:
- catalog_path = website_dir / "index.toml"
+ catalog_path = published_dir / "index.toml"
catalog = load_toml(catalog_path)
if set(catalog) != {"schema_version", "agents"}:
raise CheckError(f"{catalog_path}: expected only schema_version and agents")
@@ -314,7 +331,7 @@ def validate_catalog(
raise CheckError(f"{catalog_path}: unsafe path for {agent_id}: {rel_path}")
if agent_id not in bundled:
raise CheckError(f"{catalog_path}: unknown agent {agent_id}; binary cannot identify it")
- manifest_path = website_dir / rel_path
+ manifest_path = published_dir / rel_path
manifest = validate_manifest(manifest_path, engine_version)
if manifest["id"] != agent_id:
raise CheckError(f"{manifest_path}: id {manifest['id']} does not match catalog {agent_id}")
@@ -322,17 +339,17 @@ def validate_catalog(
bundled_path, bundled_manifest = bundled[agent_id]
cmp = compare_versions(manifest["version"], bundled_manifest["version"], manifest_path)
- staged_manifest = STAGED_WEBSITE_MANIFESTS.get(agent_id)
- website_digest = hashlib.sha256(manifest_path.read_bytes()).hexdigest()
+ staged_manifest = STAGED_PUBLISHED_MANIFESTS.get(agent_id)
+ published_digest = hashlib.sha256(manifest_path.read_bytes()).hexdigest()
stages_new_engine_manifest = (
staged_manifest
- == (bundled_manifest["version"], manifest["version"], website_digest)
+ == (bundled_manifest["version"], manifest["version"], published_digest)
and bundled_manifest["min_engine_version"] == engine_version
and manifest["min_engine_version"] < bundled_manifest["min_engine_version"]
)
if cmp < 0 and not stages_new_engine_manifest:
raise CheckError(
- f"{manifest_path}: website version {manifest['version']} is lower than bundled "
+ f"{manifest_path}: published version {manifest['version']} is lower than bundled "
f"{bundled_manifest['version']} in {bundled_path}"
)
if cmp == 0 and manifest_path.read_text(encoding="utf-8") != bundled_path.read_text(encoding="utf-8"):
@@ -341,13 +358,22 @@ def validate_catalog(
)
missing = sorted(set(bundled) - set(seen))
- if missing:
- raise CheckError(f"{catalog_path}: missing bundled agent(s): {', '.join(missing)}")
+ unexpected_missing = []
+ for agent_id in missing:
+ bundled_path, bundled_manifest = bundled[agent_id]
+ staged = UNPUBLISHED_BUNDLED_MANIFESTS.get(agent_id) if allow_unpublished else None
+ digest = hashlib.sha256(bundled_path.read_bytes()).hexdigest()
+ if staged != (bundled_manifest["version"], digest):
+ unexpected_missing.append(agent_id)
+ if unexpected_missing:
+ raise CheckError(
+ f"{catalog_path}: missing bundled agent(s): {', '.join(unexpected_missing)}"
+ )
catalog_paths = set(seen.values()) | {"index.toml"}
- extra = sorted(path.name for path in website_dir.glob("*.toml") if path.name not in catalog_paths)
+ extra = sorted(path.name for path in published_dir.glob("*.toml") if path.name not in catalog_paths)
if extra:
- raise CheckError(f"{website_dir}: TOML file(s) not listed in catalog: {', '.join(extra)}")
+ raise CheckError(f"{published_dir}: TOML file(s) not listed in catalog: {', '.join(extra)}")
def main() -> int:
@@ -355,10 +381,15 @@ def main() -> int:
try:
engine_version = read_engine_version(args.engine_version)
bundled = load_manifest_dir(args.bundled_dir, engine_version)
- if args.require_website or args.website_dir.exists():
- if not args.website_dir.is_dir():
- raise CheckError(f"{args.website_dir}: website manifest directory is missing")
- validate_catalog(args.website_dir, bundled, engine_version)
+ if args.require_published or args.require_all_published or args.published_dir.exists():
+ if not args.published_dir.is_dir():
+ raise CheckError(f"{args.published_dir}: published manifest directory is missing")
+ validate_catalog(
+ args.published_dir,
+ bundled,
+ engine_version,
+ allow_unpublished=not args.require_all_published,
+ )
except CheckError as exc:
print(f"error: {exc}", file=sys.stderr)
return 1
diff --git a/scripts/changelog.py b/scripts/changelog.py
index 9a96ea4e..9fcae9cd 100644
--- a/scripts/changelog.py
+++ b/scripts/changelog.py
@@ -16,7 +16,7 @@ DEFAULT_LIVE_MANIFEST_URL = "https://herdr.dev/latest.json"
SECTION_RE = re.compile(r"^##\s+(?:\[(?P<bracketed>[^\]]+)\]|(?P<plain>.+?))\s*$", re.MULTILINE)
VERSION_WITH_DATE_RE = re.compile(r"^(?P<version>.+?)\s+-\s+\d{4}-\d{2}-\d{2}$")
DEFAULT_RELEASE_REPO = "herdrdev/herdr"
-DEFAULT_LATEST_JSON_PATH = Path("website/latest.json")
+DEFAULT_LATEST_JSON_PATH = Path("distribution/latest.json")
DEFAULT_PRODUCT_ANNOUNCEMENT_PATH = Path("docs/next/product-announcement.json")
PROTOCOL_SOURCE_PATH = Path("src/protocol/wire.rs")
CORE_ASSET_TARGETS = (
@@ -619,11 +619,11 @@ def verify_asset_urls_resolve(assets: dict[str, str], label: str) -> None:
def ensure_manifest_is_outdated(current_manifest: dict[str, Any], version: str) -> None:
current_version = current_manifest.get("version")
if not isinstance(current_version, str):
- raise ChangelogError("website/latest.json is missing a string version")
+ raise ChangelogError("distribution/latest.json is missing a string version")
if parse_version(current_version) >= parse_version(version):
raise ChangelogError(
- f"website/latest.json is already at v{normalize_version(current_version)}; expected something older than v{normalize_version(version)}"
+ f"distribution/latest.json is already at v{normalize_version(current_version)}; expected something older than v{normalize_version(version)}"
)
@@ -696,7 +696,7 @@ def cmd_sync_latest_json(args: argparse.Namespace) -> int:
print("next:")
print(f" git diff -- {manifest_path}")
print(f" git add {manifest_path}")
- print(f" git commit -m \"docs: update website manifest for v{version}\"")
+ print(f" git commit -m \"docs: publish release distribution for v{version}\"")
print(" git push")
return 0
@@ -763,7 +763,7 @@ def build_parser() -> argparse.ArgumentParser:
sync_latest_json = subparsers.add_parser(
"sync-latest-json",
- help="Update website/latest.json from a published GitHub release",
+ help="Update distribution/latest.json from a published GitHub release",
)
sync_latest_json.add_argument("--version", required=True)
sync_latest_json.add_argument("--repo", default=DEFAULT_RELEASE_REPO)
diff --git a/website/scripts/docs-preview.integration.test.ts b/scripts/docs/preview.integration.test.ts
index f850689c..74e54957 100644
--- a/website/scripts/docs-preview.integration.test.ts
+++ b/scripts/docs/preview.integration.test.ts
@@ -4,7 +4,7 @@ import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
import { join, resolve } from 'node:path';
import { tmpdir } from 'node:os';
-const script = resolve(import.meta.dir, 'docs-preview.mjs');
+const script = resolve(import.meta.dir, 'preview.mjs');
const temporaryDirectories: string[] = [];
afterEach(async () => {
@@ -56,7 +56,7 @@ async function fixture() {
async function writeManifest(root: string, commit: string) {
await write(
root,
- 'website/preview.json',
+ 'distribution/preview.json',
`${JSON.stringify({
schema_version: 1,
channel: 'preview',
diff --git a/website/scripts/docs-preview.mjs b/scripts/docs/preview.mjs
index c0de1fcd..9ef85728 100644
--- a/website/scripts/docs-preview.mjs
+++ b/scripts/docs/preview.mjs
@@ -7,16 +7,16 @@ import {
extractGitTree,
gitPathExists,
resolveCommit,
-} from './docs-snapshot.mjs';
+} from './snapshot.mjs';
-const websiteDir = dirname(fileURLToPath(import.meta.url));
+const scriptDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = process.env.HERDR_DOCS_REPO_ROOT
? resolve(process.env.HERDR_DOCS_REPO_ROOT)
- : resolve(websiteDir, '../..');
+ : resolve(scriptDir, '../..');
const git = createGit(repoRoot);
const sourceRoot = 'docs/next/website';
const snapshotRoot = resolve(repoRoot, 'docs/preview/website');
-const manifestPath = resolve(repoRoot, 'website/preview.json');
+const manifestPath = resolve(repoRoot, 'distribution/preview.json');
const fullShaPattern = /^[0-9a-f]{40}$/;
export async function snapshotPreview(ref) {
@@ -67,7 +67,7 @@ async function main() {
await checkPreview();
return;
}
- throw new Error('usage: node website/scripts/docs-preview.mjs check | snapshot <commit>');
+ throw new Error('usage: node scripts/docs/preview.mjs check | snapshot <commit>');
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
diff --git a/website/scripts/docs-snapshot.mjs b/scripts/docs/snapshot.mjs
index e9eaf92c..e9eaf92c 100644
--- a/website/scripts/docs-snapshot.mjs
+++ b/scripts/docs/snapshot.mjs
diff --git a/website/scripts/docs-versions.integration.test.ts b/scripts/docs/versions.integration.test.ts
index 2eba45cb..a52be1be 100644
--- a/website/scripts/docs-versions.integration.test.ts
+++ b/scripts/docs/versions.integration.test.ts
@@ -4,21 +4,20 @@ import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promis
import { join, resolve } from 'node:path';
import { tmpdir } from 'node:os';
-const script = resolve(import.meta.dir, 'docs-versions.mjs');
-const prepareScript = resolve(import.meta.dir, 'prepare-docs.mjs');
+const script = resolve(import.meta.dir, 'versions.mjs');
const temporaryDirectories: string[] = [];
afterEach(async () => {
- await Promise.all(temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true })));
+ await Promise.all(
+ temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true })),
+ );
});
describe('documentation release publishing', () => {
- test('snapshots tagged next docs and switches stable to generated snapshots', async () => {
+ test('publishes immutable tagged snapshots and validates maintained corrections', async () => {
const root = await mkdtemp(join(tmpdir(), 'herdr-docs-'));
temporaryDirectories.push(root);
- await write(root, 'website/src/content/docs/index.mdx', 'stable docs\n');
- await write(root, 'website/src/data/config-reference.json', '{"stable":true}\n');
- await write(root, 'website/latest.json', '{"version":"0.9.0"}\n');
+ await write(root, 'distribution/latest.json', '{"version":"0.9.0"}\n');
await write(root, 'README.md', 'stable readme\n');
await write(root, 'README.zh-CN.md', 'stable readme zh-cn\n');
const nextDocs = '---\ntitle: Documentation\n---\n\nnext docs\n';
@@ -37,11 +36,11 @@ describe('documentation release publishing', () => {
runScript(root, ['publish', 'v1.0.0']);
- await expect(read(root, 'website/src/content/docs/index.mdx')).rejects.toThrow();
- await expect(read(root, 'website/src/data/config-reference.json')).rejects.toThrow();
expect(await read(root, 'README.md')).toBe('next readme\n');
expect(await read(root, 'README.zh-CN.md')).toBe('next readme zh-cn\n');
- expect(await read(root, 'docs/versions/1.0.0/website/src/content/docs/index.mdx')).toBe(nextDocs);
+ expect(await read(root, 'docs/versions/1.0.0/website/src/content/docs/index.mdx')).toBe(
+ nextDocs,
+ );
const manifest = JSON.parse(await read(root, 'docs/versions/manifest.json'));
expect(manifest.current).toBe('1.0.0');
@@ -53,46 +52,11 @@ describe('documentation release publishing', () => {
source: 'docs/next/website/src/content/docs',
});
- const previewCommit = git(root, ['rev-parse', 'HEAD']).trim();
- await write(root, 'docs/preview/website/src/content/docs/index.mdx', 'preview docs\n');
- await write(
- root,
- 'docs/preview/website/src/data/config-reference.json',
- '{"preview":true}\n',
- );
- await write(
- root,
- 'website/preview.json',
- `${JSON.stringify({ build_id: 'preview-test', commit: previewCommit })}\n`,
- );
- runPrepare(root);
- const stableDocs = await read(root, 'website/src/content/docs/index.mdx');
- expect(stableDocs).toContain('next docs');
- expect(stableDocs).toContain(
- 'editUrl: https://github.com/herdrdev/herdr/blob/master/docs/versions/1.0.0/website/src/content/docs/index.mdx',
- );
- const versionedDocs = await read(
- root,
- 'website/src/content/docs/_versions/1.0.0/index.mdx',
- );
- expect(versionedDocs).toContain('next docs');
- expect(versionedDocs).toContain(
- 'editUrl: https://github.com/herdrdev/herdr/blob/master/docs/versions/1.0.0/website/src/content/docs/index.mdx',
- );
- expect(await read(root, 'website/src/content/docs/preview/index.mdx')).toContain(
- 'Preview build `preview-test`',
- );
- expect(await read(root, 'website/src/data/config-reference.json')).toBe('{"next":true}\n');
-
- await write(root, 'website/latest.json', '{"version":"1.0.0"}\n');
+ await write(root, 'distribution/latest.json', '{"version":"1.0.0"}\n');
runScript(root, ['check']);
const correctedDocs = '---\ntitle: Documentation\n---\n\ncorrected docs\n';
- await write(
- root,
- 'docs/versions/1.0.0/website/src/content/docs/index.mdx',
- correctedDocs,
- );
+ await write(root, 'docs/versions/1.0.0/website/src/content/docs/index.mdx', correctedDocs);
await write(
root,
'docs/versions/1.0.0/website/src/data/config-reference.json',
@@ -104,19 +68,6 @@ describe('documentation release publishing', () => {
runScript(root, ['publish', 'v1.0.0']);
expect(await read(root, 'README.md')).toBe('post-release correction\n');
- runPrepare(root);
- expect(await read(root, 'website/src/content/docs/index.mdx')).toContain('corrected docs');
- expect(await read(root, 'website/src/content/docs/_versions/1.0.0/index.mdx')).toContain(
- 'corrected docs',
- );
- expect(await read(root, 'website/src/data/config-reference.json')).toBe(
- '{"corrected":true}\n',
- );
- const versionReferences = JSON.parse(
- await read(root, 'website/src/data/config-reference-versions.json'),
- );
- expect(versionReferences['1.0.0']).toEqual({ corrected: true });
-
runScript(root, ['publish', 'v0.9.0']);
const archivedManifest = JSON.parse(await read(root, 'docs/versions/manifest.json'));
expect(archivedManifest.current).toBe('1.0.0');
@@ -135,10 +86,7 @@ describe('documentation release publishing', () => {
correctedArchivedDocs,
);
- const archivedDocsRoot = resolve(
- root,
- 'docs/versions/0.9.0/website/src/content/docs',
- );
+ const archivedDocsRoot = resolve(root, 'docs/versions/0.9.0/website/src/content/docs');
await rm(archivedDocsRoot, { recursive: true, force: true });
expect(() => runScript(root, ['check'])).toThrow();
await write(
@@ -155,8 +103,6 @@ describe('documentation release publishing', () => {
delete archivedManifest.versions[0].commit;
await write(root, 'docs/versions/manifest.json', `${JSON.stringify(archivedManifest)}\n`);
expect(() => runScript(root, ['check'])).toThrow();
- // This test runs a dozen git and node subprocesses; slow CI builders can
- // exceed the 5s default timeout.
}, 30_000);
});
@@ -181,11 +127,3 @@ function runScript(root: string, args: string[]) {
stdio: 'pipe',
});
}
-
-function runPrepare(root: string) {
- execFileSync('node', [prepareScript, '--docs-only'], {
- cwd: root,
- env: { ...process.env, HERDR_DOCS_REPO_ROOT: root },
- stdio: 'pipe',
- });
-}
diff --git a/website/scripts/docs-versions.mjs b/scripts/docs/versions.mjs
index 0923d683..163d3ae6 100644
--- a/website/scripts/docs-versions.mjs
+++ b/scripts/docs/versions.mjs
@@ -8,16 +8,15 @@ import {
gitTreesEqual,
listDocumentationPaths,
resolveCommit,
-} from './docs-snapshot.mjs';
+} from './snapshot.mjs';
-const websiteDir = dirname(fileURLToPath(import.meta.url));
+const scriptDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = process.env.HERDR_DOCS_REPO_ROOT
? resolve(process.env.HERDR_DOCS_REPO_ROOT)
- : resolve(websiteDir, '../..');
+ : resolve(scriptDir, '../..');
const versionsDir = resolve(repoRoot, 'docs/versions');
const manifestPath = resolve(versionsDir, 'manifest.json');
-const stableDocsDir = resolve(repoRoot, 'website/src/content/docs');
-const stableReferencePath = resolve(repoRoot, 'website/src/data/config-reference.json');
+const latestManifestPath = resolve(repoRoot, 'distribution/latest.json');
const git = createGit(repoRoot);
const VERSION_PATTERN = /^v?(\d+\.\d+\.\d+)$/;
@@ -111,7 +110,7 @@ export async function backfillVersions() {
process.stdout.write(`snapshotted ${tag}\n`);
}
- const current = JSON.parse(await readFile(resolve(repoRoot, 'website/latest.json'), 'utf8')).version;
+ const current = JSON.parse(await readFile(latestManifestPath, 'utf8')).version;
await writeManifest({
schema_version: 1,
stable_source: manifest.stable_source ?? 'legacy',
@@ -130,9 +129,9 @@ export async function checkVersions() {
throw new Error(`${manifestPath} has an unsupported schema`);
}
- const latest = JSON.parse(await readFile(resolve(repoRoot, 'website/latest.json'), 'utf8')).version;
+ const latest = JSON.parse(await readFile(latestManifestPath, 'utf8')).version;
if (manifest.current !== normalizeVersion(latest)) {
- throw new Error(`docs current version ${manifest.current} does not match website latest ${latest}`);
+ throw new Error(`docs current version ${manifest.current} does not match distribution latest ${latest}`);
}
const expectedOrder = sortVersionsNewestFirst(manifest.versions).map(({ version }) => version);
@@ -236,8 +235,6 @@ export async function publishVersion(tag) {
}
const metadata = await snapshotTag(tag, 'docs/next/website/src/content/docs');
- await rm(stableDocsDir, { recursive: true, force: true });
- await rm(stableReferencePath, { force: true });
for (const readme of ['README.md', 'README.zh-CN.md']) {
const nextReadme = `docs/next/${readme}`;
@@ -277,7 +274,7 @@ async function main() {
return;
}
throw new Error(
- 'usage: node website/scripts/docs-versions.mjs backfill | check | current | publish <tag>',
+ 'usage: node scripts/docs/versions.mjs backfill | check | current | publish <tag>',
);
}
diff --git a/website/scripts/docs-versions.test.ts b/scripts/docs/versions.test.ts
index dc450b37..c40ee854 100644
--- a/website/scripts/docs-versions.test.ts
+++ b/scripts/docs/versions.test.ts
@@ -1,5 +1,5 @@
import { describe, expect, test } from 'bun:test';
-import { normalizeVersion, sortVersionsNewestFirst } from './docs-versions.mjs';
+import { normalizeVersion, sortVersionsNewestFirst } from './versions.mjs';
describe('normalizeVersion', () => {
test.each([
diff --git a/scripts/preview.py b/scripts/preview.py
index fa55d623..16c52b6e 100644
--- a/scripts/preview.py
+++ b/scripts/preview.py
@@ -20,6 +20,7 @@ EXPECTED_ASSET_NAMES = {
"windows-x86_64": "herdr-windows-x86_64.zip",
}
HIDDEN_SUBJECTS = (
+ "docs: publish release distribution",
"docs: update website manifest",
"docs: update preview manifest",
"chore: approve contributor",
@@ -294,7 +295,7 @@ def main() -> int:
sub = parser.add_subparsers(required=True)
notes = sub.add_parser("notes")
- notes.add_argument("--manifest", default="website/preview.json")
+ notes.add_argument("--manifest", default="distribution/preview.json")
notes.add_argument("--previous")
notes.add_argument("--commit", required=True)
notes.add_argument("--build-id", required=True)
@@ -304,7 +305,7 @@ def main() -> int:
notes.set_defaults(func=cmd_notes)
manifest = sub.add_parser("manifest")
- manifest.add_argument("--output", default="website/preview.json")
+ manifest.add_argument("--output", default="distribution/preview.json")
manifest.add_argument("--repo", default="herdrdev/herdr")
manifest.add_argument("--tag", required=True)
manifest.add_argument("--build-id", required=True)
@@ -318,7 +319,7 @@ def main() -> int:
manifest.set_defaults(func=cmd_manifest)
current = sub.add_parser("current-commit")
- current.add_argument("--manifest", default="website/preview.json")
+ current.add_argument("--manifest", default="distribution/preview.json")
current.set_defaults(func=cmd_current_commit)
select = sub.add_parser("select-commit")
diff --git a/scripts/release_perf_smoke.sh b/scripts/release_perf_smoke.sh
index 7ce1f736..2b7972e2 100755
--- a/scripts/release_perf_smoke.sh
+++ b/scripts/release_perf_smoke.sh
@@ -37,7 +37,7 @@ trap 'exit 143' TERM
mkdir -p "$root/results"
if [[ -z "$baseline" ]]; then
- baseline_version=$(jq -er '.version' "$repo_root/website/latest.json")
+ baseline_version=$(jq -er '.version' "$repo_root/distribution/latest.json")
baseline="$root/herdr-baseline"
curl -fL --retry 3 \
"https://github.com/herdrdev/herdr/releases/download/v${baseline_version}/herdr-${platform}-${arch}" \
diff --git a/scripts/test_agent_detection_manifest_check.py b/scripts/test_agent_detection_manifest_check.py
index a9ec38d1..6c4cd726 100644
--- a/scripts/test_agent_detection_manifest_check.py
+++ b/scripts/test_agent_detection_manifest_check.py
@@ -29,21 +29,33 @@ path = "{path}"
def staged_grok_dirs(root: Path) -> tuple[Path, Path]:
bundled = root / "bundled"
- website = root / "website"
+ published = root / "published"
bundled.mkdir()
- website.mkdir()
+ published.mkdir()
(bundled / "grok.toml").write_bytes(
(check.DEFAULT_BUNDLED_DIR / "grok.toml").read_bytes()
)
- (website / "grok.toml").write_bytes(
- (check.DEFAULT_WEBSITE_DIR / "grok.toml").read_bytes()
+ (published / "grok.toml").write_bytes(
+ (check.DEFAULT_PUBLISHED_DIR / "grok.toml").read_bytes()
)
- (website / "index.toml").write_text(catalog("grok", "grok.toml"))
- return bundled, website
+ (published / "index.toml").write_text(catalog("grok", "grok.toml"))
+ return bundled, published
+
+
+def unpublished_muse_dirs(root: Path) -> tuple[Path, Path]:
+ bundled = root / "bundled"
+ published = root / "published"
+ bundled.mkdir()
+ published.mkdir()
+ (bundled / "muse.toml").write_bytes(
+ (check.DEFAULT_BUNDLED_DIR / "muse.toml").read_bytes()
+ )
+ (published / "index.toml").write_text("schema_version = 1\nagents = []\n")
+ return bundled, published
class AgentDetectionManifestCheckTests(unittest.TestCase):
- def test_validates_bundled_and_matching_website_catalog(self):
+ def test_validates_bundled_and_matching_published_catalog(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
bundled = root / "bundled"
@@ -58,7 +70,7 @@ class AgentDetectionManifestCheckTests(unittest.TestCase):
bundled_manifests = check.load_manifest_dir(bundled, engine_version=1)
check.validate_catalog(website, bundled_manifests, engine_version=1)
- def test_rejects_website_version_lower_than_bundled(self):
+ def test_rejects_published_version_lower_than_bundled(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
bundled = root / "bundled"
@@ -73,14 +85,14 @@ class AgentDetectionManifestCheckTests(unittest.TestCase):
with self.assertRaisesRegex(check.CheckError, "lower than bundled"):
check.validate_catalog(website, bundled_manifests, engine_version=1)
- def test_allows_explicitly_staged_website_manifest(self):
+ def test_allows_explicitly_staged_published_manifest(self):
with tempfile.TemporaryDirectory() as tmp:
bundled, website = staged_grok_dirs(Path(tmp))
bundled_manifests = check.load_manifest_dir(bundled, engine_version=3)
check.validate_catalog(website, bundled_manifests, engine_version=3)
- def test_rejects_mutated_staged_website_manifest(self):
+ def test_rejects_mutated_staged_published_manifest(self):
with tempfile.TemporaryDirectory() as tmp:
bundled, website = staged_grok_dirs(Path(tmp))
with (website / "grok.toml").open("a") as manifest_file:
@@ -90,7 +102,7 @@ class AgentDetectionManifestCheckTests(unittest.TestCase):
with self.assertRaisesRegex(check.CheckError, "lower than bundled"):
check.validate_catalog(website, bundled_manifests, engine_version=3)
- def test_rejects_unlisted_website_manifest_lag_for_new_engine(self):
+ def test_rejects_unlisted_published_manifest_lag_for_new_engine(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
bundled = root / "bundled"
@@ -123,6 +135,38 @@ class AgentDetectionManifestCheckTests(unittest.TestCase):
with self.assertRaisesRegex(check.CheckError, "same version"):
check.validate_catalog(website, bundled_manifests, engine_version=1)
+ def test_allows_exact_unpublished_bundled_manifest(self):
+ with tempfile.TemporaryDirectory() as tmp:
+ bundled, published = unpublished_muse_dirs(Path(tmp))
+ bundled_manifests = check.load_manifest_dir(bundled, engine_version=3)
+ check.validate_catalog(
+ published,
+ bundled_manifests,
+ engine_version=3,
+ allow_unpublished=True,
+ )
+
+ def test_release_gate_rejects_exact_unpublished_bundled_manifest(self):
+ with tempfile.TemporaryDirectory() as tmp:
+ bundled, published = unpublished_muse_dirs(Path(tmp))
+ bundled_manifests = check.load_manifest_dir(bundled, engine_version=3)
+ with self.assertRaisesRegex(check.CheckError, "missing bundled agent"):
+ check.validate_catalog(published, bundled_manifests, engine_version=3)
+
+ def test_rejects_mutated_unpublished_bundled_manifest(self):
+ with tempfile.TemporaryDirectory() as tmp:
+ bundled, published = unpublished_muse_dirs(Path(tmp))
+ with (bundled / "muse.toml").open("a") as manifest_file:
+ manifest_file.write("\n# unexpected mutation\n")
+ bundled_manifests = check.load_manifest_dir(bundled, engine_version=3)
+ with self.assertRaisesRegex(check.CheckError, "missing bundled agent"):
+ check.validate_catalog(
+ published,
+ bundled_manifests,
+ engine_version=3,
+ allow_unpublished=True,
+ )
+
def test_rejects_unknown_catalog_agent(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
diff --git a/scripts/test_package_windows_conpty.py b/scripts/test_package_windows_conpty.py
index b8d73a6c..0736208b 100644
--- a/scripts/test_package_windows_conpty.py
+++ b/scripts/test_package_windows_conpty.py
@@ -29,7 +29,7 @@ class WindowsConptyPackageTests(unittest.TestCase):
loader = (
package.PROJECT_ROOT / "vendor/portable-pty/src/win/psuedocon.rs"
).read_text(encoding="utf-8")
- installer = (package.PROJECT_ROOT / "website/install.ps1").read_text(
+ installer = (package.PROJECT_ROOT / "distribution/install.ps1").read_text(
encoding="utf-8"
)
for item in metadata["bundles"]["x86_64"]["files"]:
diff --git a/scripts/test_preview.py b/scripts/test_preview.py
index 137a13f0..0f586437 100644
--- a/scripts/test_preview.py
+++ b/scripts/test_preview.py
@@ -83,6 +83,7 @@ class PreviewNotesTests(unittest.TestCase):
def test_hidden_subjects_include_preview_manifest_commits(self):
self.assertTrue(preview.hidden_subject("docs: update preview manifest"))
self.assertTrue(preview.hidden_subject("docs: update website manifest"))
+ self.assertTrue(preview.hidden_subject("docs: publish release distribution"))
self.assertFalse(preview.hidden_subject("release: v0.7.0"))
self.assertFalse(preview.hidden_subject("fix: repair preview manifest"))
@@ -161,60 +162,6 @@ class PreviewNotesTests(unittest.TestCase):
finally:
os.chdir(original_cwd)
- def test_preview_docs_rewrite_links_to_preview_namespace(self):
- source = """---
-title: Install Herdr
----
-
-import ConfigReference from '../../components/ConfigReference.astro';
-import LocaleWidget from '../../../components/LocaleWidget.astro';
-
-[Install](/docs/install/)
-file: ../../../public/assets/logo.svg
-"""
- output = subprocess.check_output(
- ["node", "website/scripts/prepare-docs.mjs", "--rewrite-preview-doc-fixture"],
- input=source,
- text=True,
- )
- self.assertIn("[Install](/docs/preview/install/)", output)
- self.assertIn("file: ../../../../public/assets/logo.svg", output)
- self.assertIn("from '../../../components/ConfigReference.astro'", output)
- self.assertIn("from '../../../../components/LocaleWidget.astro'", output)
- self.assertIn("Preview build `2026-07-29-44b3adb12552`", output)
- self.assertIn(
- "blob/44b3adb125524ea9a55739eee3776f922f2115ad/docs/next/website/src/content/docs/",
- output,
- )
-
- def test_version_docs_rewrite_links_and_source_paths(self):
- source = """---
-title: Install Herdr
----
-
-import ConfigReference from '../../components/ConfigReference.astro';
-
-[Install](/docs/install/)
-[Skill](https://github.com/herdrdev/herdr/blob/master/SKILL.md)
-file: ../../../public/assets/logo.svg
-"""
- output = subprocess.check_output(
- [
- "node",
- "website/scripts/prepare-docs.mjs",
- "--rewrite-version-doc-fixture",
- "0.7.4",
- ],
- input=source,
- text=True,
- )
- self.assertIn("[Install](/docs/0.7.4/install/)", output)
- self.assertIn("file: ../../../../../public/assets/logo.svg", output)
- self.assertIn("from '../../../../components/ConfigReference.astro'", output)
- self.assertIn("blob/master/docs/versions/0.7.4/website/src/content/docs/index.mdx", output)
- self.assertIn("blob/v0.7.4/SKILL.md", output)
-
-
class ConventionalCommitTests(unittest.TestCase):
def test_valid_subjects_allow_scopes_and_bang(self):
self.assertTrue(conventional_commits.valid_subject("fix(update): handle preview"))
diff --git a/scripts/test_unix_installer.py b/scripts/test_unix_installer.py
index 82de55c8..ca7d3b19 100644
--- a/scripts/test_unix_installer.py
+++ b/scripts/test_unix_installer.py
@@ -11,7 +11,7 @@ from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
-INSTALLER = REPO_ROOT / "website" / "install.sh"
+INSTALLER = REPO_ROOT / "distribution" / "install.sh"
REQUIRED_COMMANDS = ("awk", "cat", "chmod", "cp", "mkdir", "mktemp", "mv", "rm")
diff --git a/scripts/windows_arm64_installer_test.ps1 b/scripts/windows_arm64_installer_test.ps1
index 7f5d7174..6d40dec0 100644
--- a/scripts/windows_arm64_installer_test.ps1
+++ b/scripts/windows_arm64_installer_test.ps1
@@ -17,7 +17,7 @@ $env:HERDR_INSTALL_DIR = Join-Path $root "bin"
$env:HERDR_CHANNEL = "preview"
Remove-Item -LiteralPath $root -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $root | Out-Null
-$installer = (Resolve-Path (Join-Path $PSScriptRoot "..\website\install.ps1")).Path
+$installer = (Resolve-Path (Join-Path $PSScriptRoot "..\distribution\install.ps1")).Path
$previousErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = "Continue"
diff --git a/scripts/windows_install_conpty_package_test.ps1 b/scripts/windows_install_conpty_package_test.ps1
index 264fafe2..055de63f 100644
--- a/scripts/windows_install_conpty_package_test.ps1
+++ b/scripts/windows_install_conpty_package_test.ps1
@@ -6,8 +6,8 @@ param(
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
-$installerPath = (Resolve-Path -LiteralPath "$PSScriptRoot\..\website\install.ps1").Path
-$bootstrapPath = (Resolve-Path -LiteralPath "$PSScriptRoot\..\website\install.cmd").Path
+$installerPath = (Resolve-Path -LiteralPath "$PSScriptRoot\..\distribution\install.ps1").Path
+$bootstrapPath = (Resolve-Path -LiteralPath "$PSScriptRoot\..\distribution\install.cmd").Path
$bootstrapContent = Get-Content -LiteralPath $bootstrapPath -Raw
foreach ($forbiddenCommand in @("Invoke-RestMethod", "Invoke-WebRequest", "Invoke-Expression", "iex")) {
if ($bootstrapContent -match "(?i)\b$forbiddenCommand\b") {
@@ -263,7 +263,7 @@ try {
$badManifest | ConvertTo-Json -Depth 5 | Out-File -LiteralPath $previewManifestPath -Encoding utf8
$downloadFailed = $false
try {
- & "$PSScriptRoot\..\website\install.ps1" `
+ & "$PSScriptRoot\..\distribution\install.ps1" `
-Channel preview `
-ManifestUrl $previewManifestUrl `
-InstallDir $installDir `
@@ -389,7 +389,7 @@ try {
}
}
- & "$PSScriptRoot\..\website\install.ps1" `
+ & "$PSScriptRoot\..\distribution\install.ps1" `
-Channel preview `
-ManifestUrl $previewManifestUrl `
-InstallDir $installDir `
@@ -402,7 +402,7 @@ try {
$junctionTarget = Join-Path $root "junction-target"
Move-Item -LiteralPath $x64HostDir -Destination $junctionTarget
New-Item -ItemType Junction -Path $x64HostDir -Target $junctionTarget | Out-Null
- & "$PSScriptRoot\..\website\install.ps1" `
+ & "$PSScriptRoot\..\distribution\install.ps1" `
-Channel preview `
-ManifestUrl $previewManifestUrl `
-InstallDir $installDir `
@@ -414,7 +414,7 @@ try {
$rejected = $false
try {
- & "$PSScriptRoot\..\website\install.ps1" `
+ & "$PSScriptRoot\..\distribution\install.ps1" `
-Channel preview `
-ManifestUrl $previewManifestUrl `
-InstallDir $installDir `
@@ -430,7 +430,7 @@ try {
}
$stableManifest | Out-File -LiteralPath $stableManifestPath -Encoding utf8
- & "$PSScriptRoot\..\website\install.ps1" `
+ & "$PSScriptRoot\..\distribution\install.ps1" `
-Channel stable `
-ManifestUrl $stableManifestUrl `
-InstallDir $installDir
@@ -465,7 +465,7 @@ exit /b 1
$preserveBin = Join-Path $root "preserve-bin"
$env:HERDR_HOME = $preserveHome
$env:Path = "$fakeBin;$oldProcessPath"
- & "$PSScriptRoot\..\website\install.ps1" `
+ & "$PSScriptRoot\..\distribution\install.ps1" `
-ManifestUrl "http://127.0.0.1:$port/candidate.json" `
-InstallDir $preserveBin `
-ExpectedBuildId "installer-test"
@@ -476,7 +476,7 @@ exit /b 1
throw "installer did not preserve the existing preview channel"
}
- & "$PSScriptRoot\..\website\install.ps1" `
+ & "$PSScriptRoot\..\distribution\install.ps1" `
-Channel stable `
-ManifestUrl $stableManifestUrl `
-InstallDir $preserveBin
diff --git a/src/update.rs b/src/update.rs
index 5359944a..a15c030f 100644
--- a/src/update.rs
+++ b/src/update.rs
@@ -688,7 +688,7 @@ fn install_downloaded_update(mut update: DownloadedUpdate) -> Result<(), String>
}
#[cfg(windows)]
-const WINDOWS_INSTALLER: &str = include_str!("../website/install.ps1");
+const WINDOWS_INSTALLER: &str = include_str!("../distribution/install.ps1");
#[cfg(windows)]
struct DownloadedWindowsUpdate {
@@ -3588,26 +3588,26 @@ mod tests {
}
#[test]
- fn checked_in_website_manifest_matches_update_schema() {
+ fn checked_in_distribution_manifest_matches_update_schema() {
#[derive(Deserialize)]
struct LegacyUpdateManifest {
assets: BTreeMap<String, String>,
}
- let json = include_str!("../website/latest.json");
+ let json = include_str!("../distribution/latest.json");
let legacy: LegacyUpdateManifest = serde_json::from_str(json)
- .expect("website/latest.json should keep legacy string asset URLs");
+ .expect("distribution/latest.json should keep legacy string asset URLs");
assert!(legacy.assets.len() >= 4);
- let manifest: UpdateManifest =
- serde_json::from_str(json).expect("website/latest.json should match updater schema");
+ let manifest: UpdateManifest = serde_json::from_str(json)
+ .expect("distribution/latest.json should match updater schema");
assert!(!manifest
.metadata_for_version(&Version::parse(&manifest.version).unwrap())
.expect("metadata")
.notes_body()
.is_empty());
- // website/latest.json describes the latest released binaries, not the
+ // distribution/latest.json describes the latest released binaries, not the
// current unreleased checkout. Its protocol is updated by the release
// flow together with the release assets.
assert!(manifest.protocol.is_some());
diff --git a/website/.gitignore b/website/.gitignore
deleted file mode 100644
index 70deacfd..00000000
--- a/website/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-node_modules/
-public/
-dist/
-.astro/
-src/content/docs/
-src/data/config-reference.json
-src/data/config-reference-preview.json
-src/data/config-reference-versions.json
-src/data/docs-versions.json
diff --git a/website/README.md b/website/README.md
deleted file mode 100644
index 8240b2f6..00000000
--- a/website/README.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# herdr website
-
-The homepage is `index.html`. Astro Starlight renders the documentation.
-
-```bash
-bun install
-bun run dev # render the unpublished docs/next draft locally
-bun run build # render only published stable and preview snapshots
-bun run build:draft # validate the unpublished draft
-```
-
-The build output is `dist/`. Configure Cloudflare Pages to use `website` as the project root and publish `dist`.
-
-Documentation has three lifecycle states:
-
-- `../docs/next/website/` is the committed, author-edited draft. Production builds never read it.
-- `../docs/preview/website/` is the latest preview release snapshot, rendered at `/docs/preview/`.
-- `../docs/versions/<version>/website/` contains maintained stable-release documentation, rendered at `/docs/<version>/`. Release CI seeds each new version from its tag. Make later factual corrections directly in that version directory, and mirror them to `docs/next` when they also apply to future releases.
-
-The version selected by `docs/versions/manifest.json` is also rendered at `/docs/`. `src/content/docs/` is entirely generated and ignored.
-
-Preview CI snapshots the selected commit and updates `preview.json` in one commit:
-
-```bash
-node website/scripts/docs-preview.mjs snapshot <commit>
-node website/scripts/docs-preview.mjs check
-```
-
-Stable release CI seeds a new maintained version from the exact tag after the GitHub Release succeeds:
-
-```bash
-node website/scripts/docs-versions.mjs publish <tag>
-node website/scripts/docs-versions.mjs check
-```
diff --git a/website/_headers b/website/_headers
deleted file mode 100644
index 47081953..00000000
--- a/website/_headers
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- X-Frame-Options: SAMEORIGIN
- X-Content-Type-Options: nosniff
- Referrer-Policy: strict-origin-when-cross-origin
-
-/assets/*
- Cache-Control: public, max-age=604800, immutable
-
-# Icon URLs stay stable for Google's favicon crawler, so they can't be
-# cache-busted with a query; keep them out of the immutable asset rule.
-/assets/favicon.png
- Cache-Control: public, max-age=86400
-
-/favicon.ico
- Content-Type: image/x-icon
- Cache-Control: public, max-age=86400
-
-/install.sh
- Content-Type: text/plain
- Content-Disposition: inline
-
-/install
- Content-Type: text/plain
- Content-Disposition: inline
-
-/install.ps1
- Content-Type: text/plain
- Content-Disposition: inline
-
-/install.cmd
- Content-Type: text/plain
- Content-Disposition: inline
-
-/latest.json
- Content-Type: application/json
- Cache-Control: public, max-age=300
-
-/agent-detection/*
- Content-Type: text/plain
- Cache-Control: public, max-age=300
-
-/llms.txt
- Content-Type: text/markdown; charset=utf-8
-
-/llms-preview.txt
- Content-Type: text/markdown; charset=utf-8
-
-/llms-small.txt
- Content-Type: text/markdown; charset=utf-8
-
-/llms-full.txt
- Content-Type: text/markdown; charset=utf-8
diff --git a/website/_redirects b/website/_redirects
deleted file mode 100644
index 2d5082a2..00000000
--- a/website/_redirects
+++ /dev/null
@@ -1,4 +0,0 @@
-/install /install.sh 200
-/sitemap.xml /sitemap-index.xml 301
-/docs/skill/ /docs/agent-skill/ 301
-/docs/api/ /docs/socket-api/ 301
diff --git a/website/assets/agent-icons/amp.svg b/website/assets/agent-icons/amp.svg
deleted file mode 100644
index 68848aa9..00000000
--- a/website/assets/agent-icons/amp.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Amp</title><path d="M15.087 23.18L12.03 24l-2.097-7.823-5.738 5.738-2.251-2.251 5.718-5.719-7.769-2.082.82-3.057 11.294 3.08 3.08 11.295z" fill="#F34E3F"></path><path d="M19.505 18.762l-3.057.82-2.564-9.573-9.572-2.564.819-3.057 11.295 3.079 3.08 11.295z" fill="#F34E3F"></path><path d="M23.893 14.374l-3.057.82-2.565-9.572L8.7 3.057 9.52 0l11.295 3.08 3.079 11.294z" fill="#F34E3F"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/antigravity.svg b/website/assets/agent-icons/antigravity.svg
deleted file mode 100644
index 3ed10ab6..00000000
--- a/website/assets/agent-icons/antigravity.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Antigravity</title><mask height="23" id="lobe-icons-antigravity-0-_R_0_" maskUnits="userSpaceOnUse" width="24" x="0" y="1"><path d="M21.751 22.607c1.34 1.005 3.35.335 1.508-1.508C17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74.815 21.1c-2.01 2.009.167 2.511 1.507 1.506 5.192-3.517 4.857-9.714 9.715-9.714 4.857 0 4.522 6.197 9.714 9.715z" fill="#fff"></path></mask><g mask="url(#lobe-icons-antigravity-0-_R_0_)"><g filter="url(#lobe-icons-antigravity-1-_R_0_)"><path d="M-1.018-3.992c-.408 3.591 2.686 6.89 6.91 7.37 4.225.48 7.98-2.043 8.387-5.633.408-3.59-2.686-6.89-6.91-7.37-4.225-.479-7.98 2.043-8.387 5.633z" fill="#FFE432"></path></g><g filter="url(#lobe-icons-antigravity-2-_R_0_)"><path d="M15.269 7.747c1.058 4.557 5.691 7.374 10.348 6.293 4.657-1.082 7.575-5.653 6.516-10.21-1.058-4.556-5.691-7.374-10.348-6.292-4.657 1.082-7.575 5.653-6.516 10.21z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-3-_R_0_)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-4-_R_0_)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-5-_R_0_)"><path d="M-7.608 14.703c3.352 3.424 9.126 3.208 12.896-.483 3.77-3.69 4.108-9.459.756-12.883C2.69-2.087-3.083-1.871-6.853 1.82c-3.77 3.69-4.108 9.458-.755 12.883z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-6-_R_0_)"><path d="M9.932 27.617c1.04 4.482 5.384 7.303 9.7 6.3 4.316-1.002 6.971-5.448 5.93-9.93-1.04-4.483-5.384-7.304-9.7-6.301-4.316 1.002-6.971 5.448-5.93 9.93z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-7-_R_0_)"><path d="M2.572-8.185C.392-3.329 2.778 2.472 7.9 4.771c5.122 2.3 11.042.227 13.222-4.63 2.18-4.855-.205-10.656-5.327-12.955-5.122-2.3-11.042-.227-13.222 4.63z" fill="#FBBC04"></path></g><g filter="url(#lobe-icons-antigravity-8-_R_0_)"><path d="M-3.267 38.686c-5.277-2.072 3.742-19.117 5.984-24.83 2.243-5.712 8.34-8.664 13.616-6.592 5.278 2.071 11.533 13.482 9.29 19.195-2.242 5.713-23.613 14.298-28.89 12.227z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-9-_R_0_)"><path d="M28.71 17.471c-1.413 1.649-5.1.808-8.236-1.878-3.135-2.687-4.531-6.201-3.118-7.85 1.412-1.649 5.1-.808 8.235 1.878s4.532 6.2 3.119 7.85z" fill="#749BFF"></path></g><g filter="url(#lobe-icons-antigravity-10-_R_0_)"><path d="M18.163 9.077c5.81 3.93 12.502 4.19 14.946.577 2.443-3.612-.287-9.727-6.098-13.658-5.81-3.931-12.502-4.19-14.946-.577-2.443 3.612.287 9.727 6.098 13.658z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-11-_R_0_)"><path d="M-.915 2.684c-1.44 3.473-.97 6.967 1.05 7.804 2.02.837 4.824-1.3 6.264-4.772 1.44-3.473.97-6.967-1.05-7.804-2.02-.837-4.824 1.3-6.264 4.772z" fill="#FFEE48"></path></g></g><defs><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="17.587" id="lobe-icons-antigravity-1-_R_0_" width="19.838" x="-3.288" y="-11.917"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="1.117"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="38.565" id="lobe-icons-antigravity-2-_R_0_" width="38.9" x="4.251" y="-13.493"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="5.4"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-3-_R_0_" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-4-_R_0_" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.595" id="lobe-icons-antigravity-5-_R_0_" width="36.632" x="-19.099" y="-10.278"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="34.087" id="lobe-icons-antigravity-6-_R_0_" width="33.533" x=".981" y="8.758"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.363"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="35.276" id="lobe-icons-antigravity-7-_R_0_" width="35.978" x="-6.143" y="-21.659"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.954"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="46.523" id="lobe-icons-antigravity-8-_R_0_" width="45.114" x="-11.96" y="-.46"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.531"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="24.054" id="lobe-icons-antigravity-9-_R_0_" width="25.094" x="10.485" y=".58"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.159"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="30.007" id="lobe-icons-antigravity-10-_R_0_" width="33.508" x="5.833" y="-12.467"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="2.669"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="26.151" id="lobe-icons-antigravity-11-_R_0_" width="22.194" x="-8.355" y="-8.876"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.303"></feGaussianBlur></filter></defs></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/claude.svg b/website/assets/agent-icons/claude.svg
deleted file mode 100644
index ed1293c4..00000000
--- a/website/assets/agent-icons/claude.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude Code</title><path clip-rule="evenodd" d="M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z" fill="#D97757" fill-rule="evenodd"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/codex-mask.svg b/website/assets/agent-icons/codex-mask.svg
deleted file mode 100644
index a864d063..00000000
--- a/website/assets/agent-icons/codex-mask.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="white" d="M9.064 3.344a4.578 4.578 0 012.285-.312c1 .115 1.891.54 2.673 1.275.01.01.024.017.037.021a.09.09 0 00.043 0 4.55 4.55 0 013.046.275l.047.022.116.057a4.581 4.581 0 012.188 2.399c.209.51.313 1.041.315 1.595a4.24 4.24 0 01-.134 1.223.123.123 0 00.03.115c.594.607.988 1.33 1.183 2.17.289 1.425-.007 2.71-.887 3.854l-.136.166a4.548 4.548 0 01-2.201 1.388.123.123 0 00-.081.076c-.191.551-.383 1.023-.74 1.494-.9 1.187-2.222 1.846-3.711 1.838-1.187-.006-2.239-.44-3.157-1.302a.107.107 0 00-.105-.024c-.388.125-.78.143-1.204.138a4.441 4.441 0 01-1.945-.466 4.544 4.544 0 01-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81 5.81 0 01-.37-.961 4.582 4.582 0 01-.014-2.298.124.124 0 00.006-.056.085.085 0 00-.027-.048 4.467 4.467 0 01-1.034-1.651 3.896 3.896 0 01-.251-1.192 5.189 5.189 0 01.141-1.6c.337-1.112.982-1.985 1.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098 0 00.065-.066 4.51 4.51 0 01.829-1.615 4.535 4.535 0 011.837-1.388zm3.482 10.565a.637.637 0 000 1.272h3.636a.637.637 0 100-1.272h-3.636zM8.462 9.23a.637.637 0 00-1.106.631l1.272 2.224-1.266 2.136a.636.636 0 101.095.649l1.454-2.455a.636.636 0 00.005-.64L8.462 9.23z"/></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/codex.svg b/website/assets/agent-icons/codex.svg
deleted file mode 100644
index c77ccfdd..00000000
--- a/website/assets/agent-icons/codex.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Codex</title><path d="M19.503 0H4.496A4.496 4.496 0 000 4.496v15.007A4.496 4.496 0 004.496 24h15.007A4.496 4.496 0 0024 19.503V4.496A4.496 4.496 0 0019.503 0z" fill="#fff"></path><path d="M9.064 3.344a4.578 4.578 0 012.285-.312c1 .115 1.891.54 2.673 1.275.01.01.024.017.037.021a.09.09 0 00.043 0 4.55 4.55 0 013.046.275l.047.022.116.057a4.581 4.581 0 012.188 2.399c.209.51.313 1.041.315 1.595a4.24 4.24 0 01-.134 1.223.123.123 0 00.03.115c.594.607.988 1.33 1.183 2.17.289 1.425-.007 2.71-.887 3.854l-.136.166a4.548 4.548 0 01-2.201 1.388.123.123 0 00-.081.076c-.191.551-.383 1.023-.74 1.494-.9 1.187-2.222 1.846-3.711 1.838-1.187-.006-2.239-.44-3.157-1.302a.107.107 0 00-.105-.024c-.388.125-.78.143-1.204.138a4.441 4.441 0 01-1.945-.466 4.544 4.544 0 01-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81 5.81 0 01-.37-.961 4.582 4.582 0 01-.014-2.298.124.124 0 00.006-.056.085.085 0 00-.027-.048 4.467 4.467 0 01-1.034-1.651 3.896 3.896 0 01-.251-1.192 5.189 5.189 0 01.141-1.6c.337-1.112.982-1.985 1.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098 0 00.065-.066 4.51 4.51 0 01.829-1.615 4.535 4.535 0 011.837-1.388zm3.482 10.565a.637.637 0 000 1.272h3.636a.637.637 0 100-1.272h-3.636zM8.462 9.23a.637.637 0 00-1.106.631l1.272 2.224-1.266 2.136a.636.636 0 101.095.649l1.454-2.455a.636.636 0 00.005-.64L8.462 9.23z" fill="url(#lobe-icons-codex-_R_0_)"></path><defs><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-codex-_R_0_" x1="12" x2="12" y1="3" y2="21"><stop stop-color="#B1A7FF"></stop><stop offset=".5" stop-color="#7A9DFF"></stop><stop offset="1" stop-color="#3941FF"></stop></linearGradient></defs></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/cursor.svg b/website/assets/agent-icons/cursor.svg
deleted file mode 100644
index a5b2ee3b..00000000
--- a/website/assets/agent-icons/cursor.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Cursor</title><path d="M22.106 5.68L12.5.135a.998.998 0 00-.998 0L1.893 5.68a.84.84 0 00-.419.726v11.186c0 .3.16.577.42.727l9.607 5.547a.999.999 0 00.998 0l9.608-5.547a.84.84 0 00.42-.727V6.407a.84.84 0 00-.42-.726zm-.603 1.176L12.228 22.92c-.063.108-.228.064-.228-.061V12.34a.59.59 0 00-.295-.51l-9.11-5.26c-.107-.062-.063-.228.062-.228h18.55c.264 0 .428.286.296.514z"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/droid.png b/website/assets/agent-icons/droid.png
deleted file mode 100644
index 7a2f42b4..00000000
--- a/website/assets/agent-icons/droid.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/agent-icons/github-copilot.svg b/website/assets/agent-icons/github-copilot.svg
deleted file mode 100644
index 3cbf22a5..00000000
--- a/website/assets/agent-icons/github-copilot.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>GithubCopilot</title><path d="M19.245 5.364c1.322 1.36 1.877 3.216 2.11 5.817.622 0 1.2.135 1.592.654l.73.964c.21.278.323.61.323.955v2.62c0 .339-.173.669-.453.868C20.239 19.602 16.157 21.5 12 21.5c-4.6 0-9.205-2.583-11.547-4.258-.28-.2-.452-.53-.453-.868v-2.62c0-.345.113-.679.321-.956l.73-.963c.392-.517.974-.654 1.593-.654l.029-.297c.25-2.446.81-4.213 2.082-5.52 2.461-2.54 5.71-2.851 7.146-2.864h.198c1.436.013 4.685.323 7.146 2.864zm-7.244 4.328c-.284 0-.613.016-.962.05-.123.447-.305.85-.57 1.108-1.05 1.023-2.316 1.18-2.994 1.18-.638 0-1.306-.13-1.851-.464-.516.165-1.012.403-1.044.996a65.882 65.882 0 00-.063 2.884l-.002.48c-.002.563-.005 1.126-.013 1.69.002.326.204.63.51.765 2.482 1.102 4.83 1.657 6.99 1.657 2.156 0 4.504-.555 6.985-1.657a.854.854 0 00.51-.766c.03-1.682.006-3.372-.076-5.053-.031-.596-.528-.83-1.046-.996-.546.333-1.212.464-1.85.464-.677 0-1.942-.157-2.993-1.18-.266-.258-.447-.661-.57-1.108-.32-.032-.64-.049-.96-.05zm-2.525 4.013c.539 0 .976.426.976.95v1.753c0 .525-.437.95-.976.95a.964.964 0 01-.976-.95v-1.752c0-.525.437-.951.976-.951zm5 0c.539 0 .976.426.976.95v1.753c0 .525-.437.95-.976.95a.964.964 0 01-.976-.95v-1.752c0-.525.437-.951.976-.951zM7.635 5.087c-1.05.102-1.935.438-2.385.906-.975 1.037-.765 3.668-.21 4.224.405.394 1.17.657 1.995.657h.09c.649-.013 1.785-.176 2.73-1.11.435-.41.705-1.433.675-2.47-.03-.834-.27-1.52-.63-1.813-.39-.336-1.275-.482-2.265-.394zm6.465.394c-.36.292-.6.98-.63 1.813-.03 1.037.24 2.06.675 2.47.968.957 2.136 1.104 2.776 1.11h.044c.825 0 1.59-.263 1.995-.657.555-.556.765-3.187-.21-4.224-.45-.468-1.335-.804-2.385-.906-.99-.088-1.875.058-2.265.394zM12 7.615c-.24 0-.525.015-.84.044.03.16.045.336.06.526l-.001.159a2.94 2.94 0 01-.014.25c.225-.022.425-.027.612-.028h.366c.187 0 .387.006.612.028-.015-.146-.015-.277-.015-.409.015-.19.03-.365.06-.526a9.29 9.29 0 00-.84-.044z"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/grok.svg b/website/assets/agent-icons/grok.svg
deleted file mode 100644
index efb1a618..00000000
--- a/website/assets/agent-icons/grok.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Grok</title><path d="M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/herdr-mask.svg b/website/assets/agent-icons/herdr-mask.svg
deleted file mode 100644
index b3d8b310..00000000
--- a/website/assets/agent-icons/herdr-mask.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g fill="white" transform="translate(0 512) scale(.1 -.1)"><path d="M2794 3710 c-129 -33 -299 -135 -359 -214 -21 -28 -26 -42 -21 -63 9 -38 154 -178 199 -192 32 -11 41 -9 104 23 171 86 354 70 475 -43 150 -138 150 -379 0 -511 -107 -95 -278 -94 -386 2 l-46 40 -11 -29 c-16 -40 -14 -122 4 -164 60 -144 264 -222 452 -174 360 92 559 494 430 868 -36 103 -81 173 -175 267 -71 72 -100 93 -180 132 -52 26 -127 54 -167 62 -96 21 -230 20 -319 -4z M2183 3695 c-116 -32 -221 -108 -273 -199 -17 -28 -30 -54 -30 -58 0 -4 20 1 45 12 66 28 220 68 294 76 64 7 65 7 137 83 40 41 71 77 69 79 -2 2 -21 8 -42 13 -55 12 -140 10 -200 -6z M2212 3388 c-159 -22 -390 -122 -559 -241 -299 -210 -585 -600 -609 -828 -12 -118 40 -251 125 -318 96 -76 178 -98 426 -116 110 -8 224 -21 254 -29 125 -34 230 -115 272 -211 11 -24 24 -81 30 -127 20 -170 65 -271 166 -374 34 -35 63 -65 63 -67 0 -1 -10 -27 -22 -57 -29 -76 -37 -259 -14 -350 42 -170 158 -318 311 -397 44 -23 98 -46 120 -52 22 -6 45 -14 51 -18 5 -5 15 -48 22 -96 6 -48 14 -92 17 -97 4 -6 415 -10 1131 -10 l1124 0 0 1584 0 1585 -55 -19 c-84 -29 -143 -68 -232 -154 l-83 -78 -54 49 c-111 102 -233 151 -391 160 -113 6 -199 -10 -298 -54 l-60 -27 -26 34 c-37 51 -120 134 -127 128 -3 -4 0 -34 7 -67 17 -89 7 -268 -21 -356 -103 -328 -377 -545 -688 -545 -161 0 -273 41 -373 137 -37 35 -66 75 -85 116 -79 173 -8 407 124 407 44 0 68 -14 117 -66 74 -78 167 -82 238 -9 60 62 72 147 33 231 -42 90 -120 130 -238 122 -50 -4 -85 -14 -131 -37 -89 -45 -122 -52 -176 -40 -92 20 -262 163 -302 253 -11 25 -21 45 -22 45 -1 -1 -30 -6 -65 -11z m-256 -505 c115 -88 129 -102 132 -131 2 -18 -2 -40 -9 -49 -7 -8 -69 -55 -138 -105 -103 -73 -130 -88 -151 -83 -35 8 -51 34 -48 74 3 31 12 42 83 92 44 31 80 61 82 66 1 4 -30 31 -69 58 -39 28 -77 56 -85 63 -18 19 -16 72 4 94 32 35 63 23 199 -79z m528 -88 c23 -24 28 -52 14 -82 l-13 -28 -141 -3 c-130 -2 -142 -1 -158 17 -23 26 -24 66 -1 91 16 18 32 20 151 20 105 0 136 -3 148 -15z"/></g></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/hermes.svg b/website/assets/agent-icons/hermes.svg
deleted file mode 100644
index 2521a105..00000000
--- a/website/assets/agent-icons/hermes.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Hermes Agent</title><path d="M5.938 12.835c.127-.039.285.02.373.143.028.038.036.092.046.14.003.014-.02.033-.04.05-.124-.098-.24-.194-.354-.291-.011-.01-.016-.027-.025-.042zM8.396 9.412c.195-.032.39-.06.588-.05a.54.54 0 01.148.026c.202.071.402.147.601.224.028.01.05.036.075.055l-.013.027a9.203 9.203 0 01-.26-.089c-.115-.038-.213-.077-.315-.098-.25-.05-.25-.046-.292-.014l.574.144c.275.139.55.276.823.417.042.022.09.057.107.098.026.06.063.076.117.072.066-.006.132-.017.213-.027l-.04.086c.051.08.142.02.216.064-.074.13-.247.09-.334.199l.061.074-.12.087c0 .106-.038.168-.306.243l.026.085-.196.042.07.124h-.25l-.007.137c-.081-.01-.161-.018-.244-.027l-.053.123c-.027-.008-.052-.011-.073-.023-.067-.038-.128-.056-.195.006-.019.017-.063.014-.093.008-.026-.006-.05-.029-.07-.042-.11.095-.11.095-.208.003-.057.046-.12.074-.186.011-.063.027-.123-.02-.178-.014-.07.007-.097-.035-.133-.07l-.13.033c-.013-.236-.194-.19-.34-.203.005-.072.05-.092.095-.094a.474.474 0 01.159.022c.164.05.32.12.496.138.203.021.405.029.601-.015.265-.059.52-.149.707-.365.049-.056.083-.127.117-.195.019-.038.02-.084-.02-.116a1.397 1.397 0 00-.382-.217c.024.12-.031.182-.115.221 0 .014-.004.025 0 .03.08.115.084.16-.007.267a1.39 1.39 0 01-.218.211.477.477 0 01-.641-.05 1.36 1.36 0 01-.133-.152c-.078-.107-.076-.108-.033-.236-.165-.08-.128-.226-.104-.364.008-.05.028-.096.049-.163-.04.014-.067.017-.087.032a.897.897 0 00-.316.357c-.007.016-.01.034-.02.047-.012.015-.034.038-.045.035-.02-.006-.037-.027-.05-.045-.008-.012-.007-.032-.012-.057h-.126l.053-.172a14.82 14.82 0 00-.039-.049l.11-.284c-.06.026-.091.044-.124.051-.03.007-.064 0-.095 0 0-.031-.01-.07.004-.092.149-.22.305-.428.593-.476z"></path><path d="M8.06 10.788c-.003-.038-.004-.075.037-.062.016.006.034.048.028.067-.01.04-.038.032-.064-.005z"></path><path clip-rule="evenodd" d="M11.981.009c.226-.012.453-.011.679 0 .247.01.495.024.74.062.401.064.798.157 1.19.273.463.138.92.299 1.356.511a7.31 7.31 0 012.948 2.642c.292.469.536.963.739 1.479.219.556.446 1.11.623 1.683.204.654.329 1.326.458 1.997.097.504.182 1.01.29 1.511.156.722.329 1.44.494 2.16.186.812.4 1.615.63 2.415.102.355.193.713.282 1.072.11.436.202.876.254 1.323.031.278.066.557.073.837a7.56 7.56 0 01-.017.88c-.037.413-.1.818-.226 1.212a5.017 5.017 0 01-.915 1.649l-.13.156.018.023c.043-.023.088-.041.127-.068.2-.138.373-.307.531-.49.4-.46.721-.973.975-1.529a3.59 3.59 0 00.325-1.72c-.024-.424-.097-.834-.3-1.213-.013-.027-.015-.06-.03-.121.05.035.082.048.101.072.107.13.22.258.315.398.33.494.46 1.052.486 1.64a3.75 3.75 0 01-.47 1.97c-.36.655-.887 1.14-1.526 1.506-.193.111-.394.21-.595.308-.157.078-.248.211-.318.365a.522.522 0 00-.033.406.359.359 0 01.013.139c-.005.077-.077.155-.14.162-.054.006-.125-.043-.15-.116a1.206 1.206 0 01-.06-.233c-.04-.314-.155-.6-.308-.87a3.906 3.906 0 00-.73-.91 2.129 2.129 0 00-.897-.524 4.093 4.093 0 00-.692-.131c-.075-.008-.15-.04-.22.01.18.06.363.11.538.18.434.173.82.43 1.18.728.308.255.58.543.794.884.098.155.186.315.227.496.027.123.042.25.067.375.013.062-.002.109-.053.144-.047.033-.122.034-.163-.01a.455.455 0 01-.08-.14c-.03-.073-.038-.159-.078-.225a7.314 7.314 0 00-1.423-1.664c-.16-.137-.329-.26-.537-.323-.376-.114-.753-.203-1.15-.154-.213.025-.427.032-.64.053a1.6 1.6 0 00-.736.278 5.14 5.14 0 00-.834.72c-.329.342-.642.699-.955 1.055-.136.155-.264.319-.314.531a5.227 5.227 0 00-.012.051.096.096 0 01-.09.076h-.31c-.046 0-.082-.048-.072-.094.023-.108.045-.216.07-.324.075-.325.19-.635.368-.917.024-.039.04-.088.104-.08l.01.049.027.077c.28-.435.571-.834.996-1.135.283-.204.584-.378.89-.55a.196.196 0 00-.098-.002c-.162.043-.325.084-.485.134-.402.124-.764.33-1.11.566-.147.1-.298.193-.414.333a7.314 7.314 0 00-1.07 1.767.845.845 0 00-.04.12.075.075 0 01-.072.056h-.494c-.04 0-.062-.051-.036-.082.123-.14.246-.282.377-.415.275-.281.58-.532.777-.884.027-.048.063-.09.095-.135.238-.333.54-.607.818-.902.082-.086.175-.16.26-.24.029-.027.053-.057.079-.085l-.018-.025-.135.041c-.034.017-.07.031-.102.05-.248.144-.494.292-.743.433-.408.23-.825.439-1.209.711-.281.2-.591.358-.889.533-.02.012-.044.015-.08.028-.015-.135.143-.201.108-.336-.033.014-.064.02-.085.038-.111.096-.227.19-.328.296-.148.157-.284.325-.425.488-.125.143-.25.286-.373.431A.153.153 0 019.89 24H8.762a.316.316 0 00.016-.042c.028-.09.085-.172.083-.28-.091-.018-.162.001-.212.077a4.45 4.45 0 00-.136.215c-.01.016-.024.03-.042.03h-.093c-.019 0-.029-.022-.017-.037.071-.088.14-.178.209-.268.001-.002-.006-.012-.012-.024-.014.004-.03.006-.045.013-.176.09-.352.181-.527.274a.363.363 0 01-.168.042H5.202c-.026 0-.039-.036-.019-.053.21-.178.402-.374.558-.605.335-.496.538-1.047.667-1.629.004-.02-.003-.043-.006-.091-.037.048-.059.072-.076.1a1.943 1.943 0 01-.334.415c-.28.258-.59.448-.983.464-.297.012-.588 0-.865-.127-.46-.21-.722-.57-.794-1.072-.025-.17-.017-.171-.182-.219A3.513 3.513 0 011.97 20.6a2.286 2.286 0 01-.808-1.13 3.569 3.569 0 01-.16-1.245c.002-.034.016-.067.024-.1.032.023.046.043.05.066.033.153.059.308.096.46.086.355.257.664.516.92.258.256.571.419.91.532.358.118.717.138 1.07-.016a1.89 1.89 0 00.621-.452c.328-.348.533-.76.648-1.223.009-.034.005-.071.007-.11-.015.006-.026.006-.03.011-.031.05-.064.1-.093.152-.284.502-.679.887-1.196 1.135-.351.17-.718.255-1.11.159a1.607 1.607 0 01-.971-.64 2.006 2.006 0 01-.368-.924 2.903 2.903 0 01.02-.886c.05-.439.466-1.17.742-1.271-.02.063-.035.112-.053.16-.043.116-.097.227-.13.345a1.901 1.901 0 00-.05.82c.033.212.09.416.204.6.147.236.346.407.62.465.11.023.225.014.338.018a.576.576 0 00.386-.131c.164-.128.282-.292.366-.481.168-.375.24-.777.309-1.179.05-.296.093-.594.133-.893.039-.281.071-.563.104-.845.026-.232.048-.464.074-.696.024-.228.052-.455.076-.683.024-.227.047-.455.069-.683.013-.14.022-.28.034-.42l.037-.417c.022-.25.041-.5.065-.748.008-.082-.02-.132-.09-.177a2.46 2.46 0 01-.492-.418c-.1-.109-.188-.228-.282-.342-.035-.042-.056-.097-.116-.118a2.084 2.084 0 00.275.597c.06.092.131.176.196.265.063.086.182.115.234.226-.028.003-.046.01-.06.006a4.74 4.74 0 01-.22-.057 2.71 2.71 0 01-1.287-.819c-.435-.487-.656-1.076-.71-1.723a5.206 5.206 0 01.014-1.06c.072-.602.22-1.186.45-1.745.155-.376.338-.741.526-1.102.205-.393.466-.75.765-1.076.512-.559 1.104-1.024 1.726-1.448.717-.49 1.478-.898 2.277-1.233C8.244.828 8.767.632 9.31.494c.655-.166 1.31-.33 1.982-.415.229-.03.458-.058.688-.07zm-1.847 22.82c-.07.06-.147.111-.207.18-.238.27-.464.549-.668.869l-.044.108a.177.177 0 00.093-.057c.174-.19.351-.378.519-.574.104-.122.195-.255.288-.386.024-.034.03-.08.046-.12l-.027-.02zm1.65-3.695a5.51 5.51 0 00-.653.593l-.37.386a.963.963 0 01-.377.25 1.372 1.372 0 01-.467.09c-.044 0-.087.006-.151.012.028.058.043.097.064.131.15.242.301.482.45.724.136.22.276.438.399.666.068.125.105.267.156.404.077.027.14-.018.202-.048.29-.135.579-.274.867-.412.213-.101.437-.186.636-.31.347-.215.68-.455 1.018-.685.015-.01.026-.028.042-.046-.023-.019-.038-.037-.056-.044-.287-.111-.527-.3-.77-.482a5.319 5.319 0 01-.506-.42 1.757 1.757 0 01-.41-.653c-.019-.049-.045-.095-.075-.156zm-5.847.264c-.06.096-.097.194-.132.293a3.38 3.38 0 01-.555 1.01c-.2.25-.455.412-.762.493-.23.06-.464.076-.7.07-.048-.002-.097.002-.158.005.016.04.021.066.035.085.1.145.23.246.4.295.157.046.316.034.498.023.181-.037.343-.115.485-.234.238-.199.402-.454.536-.732.175-.363.264-.751.342-1.144.01-.053.008-.11.011-.164zm14.945-4.586c.008.029.016.057.027.107.024.155.051.31.072.464.03.219.067.437.078.657.017.344.027.689-.014 1.033-.037.315-.063.633-.116.946a6.153 6.153 0 01-.46 1.518c-.008.018-.01.039-.02.082.047-.03.077-.042.098-.064.085-.083.17-.167.248-.255.271-.305.458-.66.596-1.043.18-.498.228-1.011.145-1.531-.103-.65-.33-1.263-.597-1.881a9.055 9.055 0 00-.024-.055l-.033.022zM5.797 8.29a.26.26 0 00.018.153c.124.251.25.501.379.75.025.049.066.09.03.163-.284.06-.578.119-.88.255.059.038.097.06.132.087.042.032.112.058.09.12-.01.033-.075.048-.117.072.017.01.043.021.067.036.166.102.33.207.447.368.138.192.229.404.188.644-.079.469-.306.85-.69 1.132-.054.04-.106.083-.161.122a.243.243 0 00-.103.245.77.77 0 00.055.195c.083.196.22.35.375.492.083.076.159.164.222.257a.37.37 0 01.025.377c-.023.05-.05.099-.076.148-.03.06-.028.111.022.162.041.042.08.089.112.138.038.058.078.079.147.05a.486.486 0 01.333-.006c.16.046.302.126.444.21.13.077.264.149.4.219.067.035.14.05.219.026.071-.022.124.01.145.076.02.064-.003.108-.074.139-.07.03-.137.063-.209.088-.1.035-.201.073-.314.077-.013-.107.11-.088.127-.159-.206-.126-.643-.145-.801-.034.063.112.035.21-.096.313-.13-.1-.025-.202.002-.3a.209.209 0 00-.249.17c-.015.101.067.216.178.224.108.007.218-.005.326-.012.06-.005.12-.027.199 0-.103.123-.248.127-.357.19.002.05.07.086.019.131-.053.048-.095-.001-.132-.03-.08-.063-.16-.126-.231-.197a.474.474 0 01-.157-.311.52.52 0 00-.043-.172c-.032-.074-.032-.137.033-.19-.018-.03-.028-.053-.045-.072a1.222 1.222 0 01-.196-.369c-.053-.137-.046-.264.048-.381.024-.03.05-.06.064-.095a.664.664 0 00.047-.168c.017-.165-.064-.287-.182-.387-.186-.156-.36-.322-.46-.551-.005-.011-.024-.017-.037-.026-.011.017-.024.027-.025.038-.019.185-.045.37-.052.557-.014.377.058.743.162 1.104.118.41.289.798.488 1.173.267.502.537 1.002.812 1.5.055.098.13.189.208.27.198.202.452.272.724.273.202 0 .404-.006.605-.026.295-.03.59-.073.884-.113.183-.025.365-.057.548-.08.21-.026.38.073.522.21.16.156.305.327.447.5.22.265.397.56.554.867.05.098.07.1.147.03.13-.121.26-.242.394-.36.067-.059.088-.12.067-.213a3.535 3.535 0 01-.085-.796c.002-.157.006-.314.018-.471.015-.224.03-.45.06-.672a59.114 59.114 0 01.362-2.298c.087-.493.182-.984.268-1.477.06-.347.118-.694.162-1.043.034-.273.055-.55.063-.825.011-.332.003-.665.002-.998 0-.077.004-.155-.01-.23-.028-.142-.01-.155-.162-.19a5.826 5.826 0 00-.607-.107c-.146-.018-.207-.053-.221-.19-.006-.049-.025-.098-.041-.146-.009-.025-.024-.048-.046-.09l-.025.264c-.009.096-.029.116-.127.115-.055 0-.11-.008-.164-.008-.476 0-.952-.008-1.426.032-.095.008-.173-.015-.226-.103-.04-.066-.088-.126-.134-.186-.063-.084-.086-.093-.182-.06-.195.068-.388.138-.582.21a2.71 2.71 0 00-.675.394.986.986 0 01-.323.168c-.033.01-.07.008-.127.013.02-.066.024-.114.047-.15.064-.105.135-.205.205-.306.023-.033.049-.063.073-.095l-.015-.023-.201.037c-.146.04-.296.07-.437.122-.148.053-.266.023-.386-.072a3.623 3.623 0 01-.733-.786l-.093-.132zm8.592 8.963l-.147.09c-.22.134-.44.266-.659.402-.093.058-.184.12-.27.188-.085.07-.124.161-.072.272.047.1.093.2.147.294.047.08.124.138.213.147.11.01.228.012.336-.012.217-.05.372-.205.528-.357a.291.291 0 00.087-.308c-.046-.18-.079-.365-.118-.547-.011-.052-.027-.103-.045-.169zm-.257-2.409c-.12.291-.205.597-.325.91-.151.433-.294.87-.435 1.323.036-.01.054-.01.067-.018.261-.16.522-.324.785-.484.054-.033.071-.078.065-.138-.012-.13-.024-.262-.034-.393l-.068-.886c-.008-.103-.02-.206-.029-.31-.009 0-.017-.002-.026-.004zm3.081-8.13l.099.285c.08.231.159.463.24.714l.58 1.952c.187.63.372 1.262.558 1.893.114.382.235.762.343 1.146.072.257.126.519.186.799.044.206.087.413.127.64.034.106.023.226.077.325l.025-.006-.068-.362c-.038-.206-.077-.412-.113-.638-.015-.07-.029-.141-.046-.211-.095-.396-.177-.796-.29-1.187-.196-.685-.413-1.364-.618-2.046-.165-.549-.322-1.1-.488-1.648-.069-.227-.15-.45-.226-.695l-.117-.336c-.037-.107-.075-.216-.115-.322-.04-.106-.084-.21-.127-.314a7.558 7.558 0 01-.027.01zM6.225 14.304c-.063-.001-.115.014-.134.083a.35.35 0 00.41.012 4.533 4.533 0 00-.276-.095zM5.23 11.98c-.026-.027-.057-.048-.075.002-.012.032-.007.07-.01.113.082-.037.082-.037.085-.115zm.062-1.189a.135.135 0 00-.088.056.197.197 0 00-.025.11c.005.152.01.306.026.457a.751.751 0 00.066.218c.061.136.157.167.288.101.055-.027.06-.054.025-.11a4.52 4.52 0 01-.129-.211c-.015-.068-.066-.131-.033-.207.04-.09-.076-.116-.074-.19V10.874c-.003-.038-.006-.087-.056-.083zm-.017-.968a.867.867 0 00-.467.127c-.076.045-.084.07-.05.158.034.087.07.173.115.254.064.117.09.125.21.077a.657.657 0 01.336-.053c.202.022.357.136.504.264l.092.077c.007-.006.014-.013.022-.018-.019-.105-.035-.226-.149-.264-.157-.053-.324-.075-.508-.117l-.24-.005c.24-.169.452-.044.687.009-.063-.115-.153-.147-.23-.193-.082-.05-.17-.092-.25-.144-.06-.037-.12-.08-.072-.172zm10.233.325c-.23-.01-.427.08-.608.211-.034.026-.06.065-.105.117.087.026.15.046.232.065.044-.015.088-.03.13-.046.306-.114.61-.115.904.031.126.063.237.04.366-.005-.02-.031-.03-.054-.045-.071a.986.986 0 00-.448-.273c-.14-.044-.284-.024-.426-.03zM7.99 6.483a.308.308 0 00.002.133c.08.321.156.643.242.962.104.387.27.75.456 1.103.02.037.061.08.098.087a.404.404 0 00.253-.051l-.472-.84c-.23-.448-.405-.92-.579-1.394zM10.397.497c-.2-.008-.405.004-.603.034-.236.035-.47.087-.7.152-.287.08-.569.18-.852.273-.04.013-.074.038-.11.058.028.014.05.018.07.014.287-.068.58-.085.873-.09.134-.002.269.009.402.025.19.024.382.048.57.09.456.104.874.3 1.265.556.464.306.888.66 1.257 1.078.205.232.395.475.56.739.17.274.315.561.449.856.273.601.456 1.232.6 1.876.04.173.07.348.1.524.017.104.065.167.17.19.122.028.2.105.22.251-.003.102-.06.174-.129.24a1.065 1.065 0 00-.268.358.164.164 0 00.083-.039c.08-.086.162-.172.235-.265a.56.56 0 00.13-.333c.009-.05.022-.1.024-.15.007-.124-.017-.15-.143-.168-.025-.004-.049-.014-.073-.015-.082-.007-.125-.063-.137-.131-.033-.198-.004-.355.247-.408.086-.018.174-.03.26-.042.158-.023.315-.053.473-.067.14-.012.19.033.226.167.008.029.018.057.021.087.019.179-.008.225-.141.288-.027.013-.055.024-.078.042a.148.148 0 00-.051.067c-.039.144.073.382.206.445l.673.32c.023.011.05.015.075.023l.018-.026c-.015-.008-.032-.013-.044-.024a2.27 2.27 0 00-.544-.32 4.898 4.898 0 00-.173-.075.203.203 0 01-.126-.191c-.003-.085.045-.154.128-.187l.059-.025c.099-.044.118-.076.112-.187a.384.384 0 00-.008-.063c-.067-.294-.123-.59-.205-.88a9.478 9.478 0 00-.826-2.036 7.465 7.465 0 00-1.39-1.805 4.536 4.536 0 00-1.177-.824 3.656 3.656 0 00-1.016-.328 6.155 6.155 0 00-.712-.074zm6.719 5.955c.01.014.018.028.038.034l-.022-.044-.016.01zM4.103 3.917a.062.062 0 01-.03.012.455.455 0 01-.04.039c-.01.01-.02.02-.045.04l-.363.354c-.088.085-.17.178-.266.253-.284.22-.425.53-.544.855a.132.132 0 00-.007.071c.013.055.033.108.052.168l.074.026c-.017.056-.03.105-.047.152-.058.164-.118.327-.175.491-.005.015.008.036.019.077.08-.175.158-.33.225-.489.228-.544.484-1.074.819-1.561.09-.133.182-.266.283-.401.004-.006.007-.013.022-.03.001-.016.003-.032.015-.04l.008-.017zm12.976 2.408a.023.023 0 01.009.019.073.073 0 00-.006.01.188.188 0 00.007.02l.018.022c.002-.007.007-.016.005-.021-.003-.01-.012-.018-.02-.038a1.331 1.331 0 01-.013-.012zM4.199 4.48c-.003.004-.008.008-.027.014-.005.013-.011.025-.031.047a2.085 2.085 0 01-.124.167c-.048.07-.116.055-.181.041-.134-.028-.228.016-.287.143-.089.187-.187.37-.273.56-.049.108-.11.216-.118.36.081.003.154.007.228.008h.228a2.563 2.563 0 01-.079.264c-.01.052-.022.103-.033.155l.02.004c.018-.046.037-.092.067-.153.066-.142.13-.285.2-.426.02-.04.034-.1.116-.092 0 .043.004.084 0 .124-.005.045-.017.09-.028.143.141.043.086.174.115.269.102-.022.104-.195.248-.144v.205l.017.002.439-1.059c-.13 0-.246-.02-.358.033-.024.011-.058-.001-.108-.004.075-.15.139-.278.211-.417a.128.128 0 01.025-.036c0-.015-.001-.03.008-.038l.006-.02c-.005.006-.01.011-.028.017-.004.012-.009.024-.026.045a.085.085 0 01-.032.033c-.123.157-.09.164-.258.106-.079-.027-.078-.028-.047-.144.028-.046.056-.093.098-.15 0-.016-.001-.032.007-.042L4.2 4.48zm2.073-.67c-.003.006-.007.011-.027.016-.094.125-.194.246-.28.377-.155.238-.301.481-.451.723-.14.224-.345.368-.575.481-.017.008-.04.006-.079.011.012-.059.016-.109.033-.153a6.076 6.076 0 01.229-.518l-.007-.02a.138.138 0 01-.035.025c-.028.05-.055.1-.093.164-.26.424-.443.817-.442.95.024.004.048.011.073.013.177.013.188.007.26-.165.03-.07.077-.12.147-.15l.175-.07c.044-.018.085-.057.146-.032.003.05-.01.11.014.145.042.062.044.125.047.193.002.049.017.098.026.147.029-.034.039-.065.05-.097.142-.39.277-.782.428-1.17.1-.256.22-.504.33-.756.013-.03.013-.067.03-.092V3.81zm3.987-.34c0 .045.01.084.021.123.042.16.094.318.124.48.024.133.023.27.028.406 0 .033-.019.067-.032.11-.094-.058-.047-.158-.106-.215h-.125c-.015.072-.01.152-.046.2-.066.085-.155.154-.236.227-.043.038-.078.018-.103-.025l-.046-.087c-.065.035-.117.069-.172.093-.116.051-.235.095-.35.147-.085.038-.09.053-.07.147.014.075.034.148.047.223.013.072.05.109.123.124.233.05.462.115.657.265.058-.102.058-.102.168-.151.03-.014.06-.03.092-.042.08-.03.115-.017.15.06.023.048.041.098.066.158.06-.14-.042-.267.017-.416.157.18.24.39.375.567a.235.235 0 00.022-.098c.002-.124 0-.247.002-.371 0-.034.013-.067.02-.1l.032-.003c.11.155.13.354.226.52a3.036 3.036 0 00-.01-.392c-.004-.045 0-.074.05-.088.08.036.116.14.215.158-.03-.275-.423-1.137-.798-1.635-.114-.127-.2-.28-.34-.386zm-2.667.696c-.019.034-.03.05-.037.067-.061.185-.125.37-.18.556-.031.105-.087.169-.195.19-.09.019-.178.052-.268.073-.038.009-.089.015-.118-.003-.024-.016-.025-.069-.036-.106-.064.076-.082.087-.17.047-.133-.062-.262-.135-.393-.201-.048-.025-.093-.063-.17-.03-.043.12-.091.25-.137.382-.099.28-.087.242.095.453.046.048.102.03.154.023.054-.009.106-.03.16-.036.13-.013.26-.08.367-.015.204-.064.387-.122.571-.178.05-.015.089.005.114.054.022.042.034.093.082.121.038-.056-.013-.128.063-.178l.14.241-.042-1.46zm.278.358c-.096-.01-.107.01-.11.108-.002.038-.003.078.002.115.03.2.099.386.174.57.002.006.012.01.022.015l.078-.05c.052.036.081.088.153.088.205-.002.41.014.616.012.099-.001.158.042.205.12.018.03.024.077.088.066l-.08-.394c-.05-.195-.085-.395-.172-.589-.057.057-.114.068-.18.046a.72.72 0 00-.135-.028c-.22-.028-.44-.059-.66-.08zm10.254-1.727c.089.163.155.316.139.491-.016.168.026.342-.044.516-.047-.033-.088-.082-.112-.075-.117.035-.164-.057-.227-.115a4.772 4.772 0 01-.286-.29l-.104-.113a4.856 4.856 0 01-.023.019c.035.046.07.093.11.156.04.064.084.127.122.193.034.058.065.118.031.205-.082-.01-.164-.019-.246-.032-.06-.01-.101 0-.124.07-.031.098-.037.096-.15.09.02.042.036.08.057.116.041.074.03.138-.03.196-.06.06-.118.122-.178.181a.175.175 0 01-.185.046c-.222-.061-.447-.113-.67-.174-.032-.009-.063-.04-.086-.068-.03-.04-.052-.087-.08-.13-.044-.07-.09-.138-.136-.207a.18.18 0 00-.014.105c.012.127.03.253.035.38.005.1-.024.12-.121.104-.104-.017-.206-.04-.31-.058-.064-.012-.131-.028-.202.03l.081.208c.09 0 .166-.01.237.002a.819.819 0 01.458.251c.078.083.154.168.241.26l.018-.005c-.004-.006-.008-.013-.01-.04.014-.056-.062-.118.018-.178.031.03.064.057.088.09.058.078.111.159.169.257l.089.141.024-.013a2093.819 2093.819 0 01-.427-.934c.055.007.083.007.108.016.193.07.385.142.577.216.074.028.147.06.219.094.062.028.112.018.157-.033.05-.056.102-.112.154-.167.05-.051.095-.046.132.014.016.025.026.053.04.08.071.138.143.277.217.433l.159.308.025-.011c-.044-.106-.07-.218-.138-.334-.057-.182-.168-.346-.206-.545.136.034.362.326.567.732l.057.074.018-.011a1.563 1.563 0 01-.052-.127c-.046-.145-.097-.29-.136-.436-.022-.083-.036-.173.022-.26l.109.058-.026-.207.027-.016c.022.02.05.036.065.06.073.108.143.22.215.33.01.016.029.029.043.043-.036-.217-.2-.38-.229-.626l.155.112c.014-.166.012-.319.042-.465.032-.158-.023-.297-.063-.445.024.004.036.006.055.025.092.124.183.249.277.371.02.027.05.047.069.087l.04.063.019-.015a.293.293 0 01-.053-.082 27.922 27.922 0 01-.332-.49c-.221-.311-.363-.467-.485-.521zm-6.57.327c-.003.161.092.275.069.415l-.368.087c.09.139.032.237-.052.331-.05.057-.092.122-.143.178-.037.04-.046.078-.018.126l.16.275c.029.048.072.066.128.064.076-.003.152 0 .228-.001.116-.003.216.022.275.137.006.014.02.024.044.052.004-.059-.003-.098.01-.13.016-.04.04-.099.072-.108.084-.023.173-.024.26-.03.013-.001.027.018.04.029l.071.065c.019-.11-.082-.198-.024-.31l.126.04c-.026-.123-.07-.245-.071-.366 0-.123.051-.243.115-.36.107.062.16.156.234.253.183.265.36.533.494.834.165-.078.27.068.407.088-.003-.106-.133-.441-.197-.492a.142.142 0 00-.102-.028c-.06.011-.119.039-.191.063-.025-.039-.056-.078-.077-.122a3.936 3.936 0 00-.473-.783c-.076-.094-.16-.182-.228-.26l-.391.285c-.049.035-.094.03-.132-.017l-.169-.207c-.025-.03-.053-.059-.097-.108z"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/kimi.svg b/website/assets/agent-icons/kimi.svg
deleted file mode 100644
index 83878fa2..00000000
--- a/website/assets/agent-icons/kimi.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Kimi</title><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z" fill="#1783FF"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z" fill="#fff"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/kiro-mask.svg b/website/assets/agent-icons/kiro-mask.svg
deleted file mode 100644
index c01b543b..00000000
--- a/website/assets/agent-icons/kiro-mask.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg"><path d="M398.554 818.914C316.315 1001.03 491.477 1046.74 620.672 940.156C658.687 1059.66 801.052 970.473 852.234 877.795C964.787 673.567 919.318 465.357 907.64 422.374C827.637 129.443 427.623 128.946 358.8 423.865C342.651 475.544 342.402 534.18 333.458 595.051C328.986 625.86 325.507 645.488 313.83 677.785C306.873 696.424 297.68 712.819 282.773 740.645C259.915 783.881 269.604 867.113 387.87 823.883L399.051 818.914H398.554Z" fill="white"/><path d="M636.123 549.353C603.328 549.353 598.359 510.097 598.359 486.742C598.359 465.623 602.086 448.977 609.293 438.293C615.504 428.852 624.697 424.131 636.123 424.131C647.555 424.131 657.492 428.852 664.447 438.541C672.398 449.474 676.623 466.12 676.623 486.742C676.623 525.998 661.471 549.353 636.375 549.353H636.123Z" fill="black"/><path d="M771.24 549.353C738.445 549.353 733.477 510.097 733.477 486.742C733.477 465.623 737.203 448.977 744.41 438.293C750.621 428.852 759.814 424.131 771.24 424.131C782.672 424.131 792.609 428.852 799.564 438.541C807.516 449.474 811.74 466.12 811.74 486.742C811.74 525.998 796.588 549.353 771.492 549.353H771.24Z" fill="black"/></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/kiro.svg b/website/assets/agent-icons/kiro.svg
deleted file mode 100644
index 5fe3cf68..00000000
--- a/website/assets/agent-icons/kiro.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<svg width="1200" height="1200" viewBox="0 0 1200 1200" fill="none" xmlns="http://www.w3.org/2000/svg">
-<rect width="1200" height="1200" rx="260" fill="#9046FF"/>
-<mask id="mask0_1106_4856" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="272" y="202" width="655" height="796">
-<path d="M926.578 202.793H272.637V997.857H926.578V202.793Z" fill="white"/>
-</mask>
-<g mask="url(#mask0_1106_4856)">
-<path d="M398.554 818.914C316.315 1001.03 491.477 1046.74 620.672 940.156C658.687 1059.66 801.052 970.473 852.234 877.795C964.787 673.567 919.318 465.357 907.64 422.374C827.637 129.443 427.623 128.946 358.8 423.865C342.651 475.544 342.402 534.18 333.458 595.051C328.986 625.86 325.507 645.488 313.83 677.785C306.873 696.424 297.68 712.819 282.773 740.645C259.915 783.881 269.604 867.113 387.87 823.883L399.051 818.914H398.554Z" fill="white"/>
-<path d="M636.123 549.353C603.328 549.353 598.359 510.097 598.359 486.742C598.359 465.623 602.086 448.977 609.293 438.293C615.504 428.852 624.697 424.131 636.123 424.131C647.555 424.131 657.492 428.852 664.447 438.541C672.398 449.474 676.623 466.12 676.623 486.742C676.623 525.998 661.471 549.353 636.375 549.353H636.123Z" fill="black"/>
-<path d="M771.24 549.353C738.445 549.353 733.477 510.097 733.477 486.742C733.477 465.623 737.203 448.977 744.41 438.293C750.621 428.852 759.814 424.131 771.24 424.131C782.672 424.131 792.609 428.852 799.564 438.541C807.516 449.474 811.74 466.12 811.74 486.742C811.74 525.998 796.588 549.353 771.492 549.353H771.24Z" fill="black"/>
-</g>
-</svg>
diff --git a/website/assets/agent-icons/mastracode.svg b/website/assets/agent-icons/mastracode.svg
deleted file mode 100644
index 10829437..00000000
--- a/website/assets/agent-icons/mastracode.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0.5 5.655 33.069 20.691" fill="none">
- <path d="m 4.99805,17.3481 c 2.48432,0 4.49804,2.0147 4.49804,4.4991 -1.9e-4,2.4841 -2.01384,4.498 -4.49804,4.498 C 2.51394,26.3451 0.500196,24.3313 0.5,21.8472 0.5,19.3629 2.51382,17.3483 4.99805,17.3481 Z M 10.8867,5.65479 c 2.4842,0 4.4979,2.01388 4.4981,4.49801 0,0.3397 -0.0378,0.6704 -0.1093,0.9884 -0.3137,1.395 -0.5802,2.9769 0.2173,4.1636 l 1.2647,1.8819 c 0.0788,0.1172 0.2152,0.1796 0.3562,0.1711 0.1232,-0.0074 0.2388,-0.0687 0.3077,-0.1712 l 1.2662,-1.8846 c 0.7896,-1.1752 0.536,-2.7394 0.2329,-4.1224 -0.0682,-0.3109 -0.1041,-0.6339 -0.1041,-0.9652 3e-4,-2.48416 2.0149,-4.49809 4.499,-4.49809 2.484,2.2e-4 4.4978,2.01407 4.4981,4.49809 0,0.3792 -0.047,0.7475 -0.1355,1.0993 -0.3233,1.2855 -0.5963,2.7204 0.0666,3.8682 l 1.2144,2.1029 c 0.0229,0.0397 0.0655,0.0633 0.1113,0.0633 2.4842,2e-4 4.4981,2.0148 4.4981,4.4991 -2e-4,2.4841 -2.014,4.4979 -4.4981,4.498 -2.4842,0 -4.4978,-2.0139 -4.498,-4.498 0,-0.3875 0.0489,-0.7636 0.141,-1.1223 0.3325,-1.2956 0.6165,-2.745 -0.0524,-3.9033 l -1.1565,-2.003 c -0.0388,-0.0672 -0.1113,-0.1052 -0.189,-0.1052 -0.0171,0 -0.033,0.0075 -0.0426,0.0217 l -1.2832,1.9092 c -0.8036,1.1956 -0.5274,2.7915 -0.2056,4.1956 0.0742,0.3238 0.1135,0.6609 0.1135,1.0073 -2e-4,2.484 -2.0141,4.4978 -4.4981,4.498 -2.4842,0 -4.4988,-2.0139 -4.499,-4.498 0,-0.2604 0.0222,-0.5156 0.0647,-0.7638 0.2208,-1.2886 0.3808,-2.7164 -0.3484,-3.8015 L 11.7419,15.9801 C 11.1829,15.1483 10.2191,14.7141 9.28286,14.3567 7.5906,13.7106 6.38867,12.0721 6.38867,10.1528 6.38886,7.66869 8.40254,5.65482 10.8867,5.65479 Z" fill="#000"/>
-</svg>
diff --git a/website/assets/agent-icons/opencode.svg b/website/assets/agent-icons/opencode.svg
deleted file mode 100644
index 9c4cb89e..00000000
--- a/website/assets/agent-icons/opencode.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>opencode</title><path d="M16 6H8v12h8V6zm4 16H4V2h16v20z"></path></svg> \ No newline at end of file
diff --git a/website/assets/agent-icons/pi.svg b/website/assets/agent-icons/pi.svg
deleted file mode 100644
index df44f948..00000000
--- a/website/assets/agent-icons/pi.svg
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800">
- <path fill="#fff" fill-rule="evenodd" d="
- M165.29 165.29
- H517.36
- V400
- H400
- V517.36
- H282.65
- V634.72
- H165.29
- Z
- M282.65 282.65
- V400
- H400
- V282.65
- Z
- "/>
- <path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/>
-</svg>
diff --git a/website/assets/agent-icons/qoder-mask.svg b/website/assets/agent-icons/qoder-mask.svg
deleted file mode 100644
index b1d33694..00000000
--- a/website/assets/agent-icons/qoder-mask.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg fill="currentColor" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Qoder</title><path d="M23.376 14.458v-4.056c0-2.304-1.003-4.154-2.748-5.075L11.612.574l-.046.086-.045.086c1.68.886 2.644 2.673 2.644 4.902v4.056a7.928 7.928 0 01-.014.454l-.005.061c-.005.081-.01.164-.018.245a4.897 4.897 0 01-.011.1l-.01.076c-.008.068-.015.135-.025.203l-.018.113-.01.058a9.99 9.99 0 01-.098.513l-.007.03a7.209 7.209 0 01-.074.294l-.024.086c-.027.099-.056.197-.087.296l-.027.085a9.592 9.592 0 01-.111.323l-.033.085-.018.046c-.032.082-.064.166-.098.248-.019.048-.04.096-.061.145l-.007.017a6 6 0 01-.084.187c-.024.056-.05.11-.077.165-.03.061-.058.122-.089.182a9.423 9.423 0 01-.176.332c-.03.056-.062.111-.094.167-.031.053-.062.108-.095.16-.033.055-.066.11-.101.164-.033.053-.065.104-.1.155-.034.055-.07.107-.111.169l-.099.144a15.193 15.193 0 01-.34.457c-.04.05-.08.102-.121.151l-.107.128-.007.008a6.987 6.987 0 01-.262.298l-.149.16-.116.12a9.562 9.562 0 01-.204.198l-.03.03-.072.069a9.05 9.05 0 01-.263.235l-.025.022-.029.026-.042.035a11.7 11.7 0 01-.22.18l-.07.055-.018.013a8.904 8.904 0 01-.194.146c-.029.02-.057.042-.086.063a7.7 7.7 0 01-.22.152l-.057.04a8.865 8.865 0 01-.293.185l-.062.037a10.424 10.424 0 01-.307.173l-.037.02-.196.103-.108.052-.012.006a6.196 6.196 0 01-.315.143c-.065.028-.13.054-.196.08l-.035.014-.086.034c-.07.026-.143.05-.215.075l-.039.014-.064.023a8.056 8.056 0 01-.323.097l-.63.173a7.285 7.285 0 01-.33.08l-.07.015c-.053.012-.104.023-.157.032l-.065.011-.085.015a2.332 2.332 0 01-.194.027l-.085.01a4.715 4.715 0 01-.16.018l-.034.003a4.861 4.861 0 01-.246.016h-.033a2.714 2.714 0 01-.155.005h-.106a3.384 3.384 0 01-.225-.007H4.86l-.15-.012-.066-.006a5.586 5.586 0 01-.187-.02l-.04-.005a5.14 5.14 0 01-.219-.035l-.054-.01a6.943 6.943 0 01-.347-.082l-.03-.008-.038-.01a5.034 5.034 0 01-.269-.086l-.063-.023a4.216 4.216 0 01-.188-.073l-.071-.031-.016-.007a4.959 4.959 0 01-.16-.074l-.026-.013a.164.164 0 00-.014-.007l-.671-.351.486.486h.016l8.995 4.742.093.048.03.014.02.01c.056.026.111.052.169.076l.016.008.073.032.195.076.022.008a.718.718 0 01.03.012l.014.004a4.693 4.693 0 00.323.1l.027.007c.073.02.147.038.22.055l.018.004.027.006.066.013.088.016c.075.014.15.026.226.038l.042.004c.064.009.128.016.193.022l.126.012.06.003.05.002.098.005c.046.002.094.002.14.003h.12c.05 0 .1-.002.161-.005h.033l.07-.004a6.17 6.17 0 00.184-.014l.033-.003a.753.753 0 00.058-.005l.108-.012.081-.01.08-.01.129-.021.082-.014.071-.012c.054-.01.107-.021.16-.033l.066-.013.059-.013c.096-.022.192-.046.287-.073l.63-.172a7.354 7.354 0 00.397-.122l.04-.015c.075-.025.149-.051.222-.078.032-.011.062-.024.093-.037l.03-.012c.067-.027.135-.054.2-.082l.128-.056.195-.09.021-.01.102-.05c.068-.034.135-.069.202-.105l.037-.02.073-.038c.08-.044.16-.092.24-.139l.026-.015a8.086 8.086 0 00.322-.2l.065-.045 1.98.902a1.748 1.748 0 002.472-1.59v-7.33l.004.004z"></path><path d="M11.617.576a3.904 3.904 0 00-.093-.047c-.016-.009-.033-.016-.05-.024a5.854 5.854 0 00-.166-.077l-.09-.04a4.094 4.094 0 00-.194-.074c-.017-.006-.035-.015-.053-.02l-.013-.005a5.18 5.18 0 00-.277-.088l-.07-.019a4.034 4.034 0 00-.219-.053c-.015-.003-.03-.008-.044-.012L10.253.1l-.057-.011a5.177 5.177 0 00-.225-.036L9.928.047a5.972 5.972 0 00-.191-.022L9.669.02a1.33 1.33 0 00-.058-.005L9.515.009a4.058 4.058 0 00-.111-.005C9.354 0 9.304 0 9.254 0h-.109c-.052 0-.106.004-.16.004L8.884.01A5.32 5.32 0 008.7.022l-.083.006h-.008c-.05.005-.1.013-.15.019l-.12.014c-.056.008-.112.018-.169.028-.037.006-.074.011-.11.018a7.054 7.054 0 00-.572.133l-.63.172c-.111.031-.22.064-.33.1-.037.011-.072.025-.108.037a12.91 12.91 0 00-.345.126c-.067.027-.133.054-.2.083l-.128.055a11.916 11.916 0 00-.318.15 7.376 7.376 0 00-.311.163c-.082.045-.16.092-.24.14a9.424 9.424 0 00-.35.218l-.016.01-.06.04a9.242 9.242 0 00-.51.37 12.54 12.54 0 00-.315.254l-.043.034-.01.007-.045.041c-.09.078-.18.158-.268.24l-.106.101c-.07.067-.139.135-.207.204l-.056.054-.063.067-.153.164-.12.133-.148.17c-.024.03-.049.057-.073.086l-.043.053a5.96 5.96 0 00-.123.155l-.118.151c-.04.053-.08.106-.118.16l-.075.101-.038.056-.107.155-.11.164a9.91 9.91 0 00-.168.265c-.012.02-.023.043-.037.063a12.43 12.43 0 00-.192.335l-.09.168c-.019.034-.04.07-.057.105-.011.022-.02.043-.032.065l-.092.188-.08.167a19.15 19.15 0 00-.083.192c-.017.038-.035.076-.05.115-.008.016-.014.034-.021.051-.035.083-.067.167-.1.253l-.051.134c-.04.11-.077.22-.113.33l-.02.057c0 .002 0 .005-.002.007l-.008.026c-.032.1-.06.2-.09.301l-.023.089c-.027.1-.052.2-.075.301l-.007.03a7.63 7.63 0 00-.057.267l-.008.048c-.015.074-.026.148-.038.223L.082 8.4c-.011.078-.02.156-.029.234-.006.051-.013.103-.017.154a6.57 6.57 0 00-.02.26c-.003.044-.007.086-.009.13-.004.128-.007.257-.007.386v4.056c0 1.478.42 2.741 1.138 3.692A4.75 4.75 0 002.73 18.67l9.015 4.753c-1.656-.874-2.728-2.685-2.73-5.051v-4.056c0-.13.004-.26.01-.39.002-.043.006-.085.01-.128.005-.088.01-.174.019-.261l.017-.155c.01-.077.018-.155.029-.234l.026-.164c.013-.074.025-.15.039-.223.02-.105.04-.21.064-.313l.008-.031c.023-.1.048-.201.075-.301l.023-.088c.028-.1.058-.202.09-.302l.008-.025.021-.063c.036-.11.073-.22.113-.33l.052-.134c.031-.085.065-.169.1-.253.022-.056.047-.111.07-.166a13.856 13.856 0 01.164-.358c.03-.063.06-.126.092-.188l.088-.172a9.22 9.22 0 01.187-.338l.096-.164c.034-.057.069-.112.104-.168l.1-.159a10.49 10.49 0 01.567-.786l.123-.155.116-.139c.05-.057.098-.115.148-.171a14.092 14.092 0 01.272-.297 9.706 9.706 0 01.432-.425c.088-.083.177-.163.268-.241l.054-.048a10.08 10.08 0 01.553-.435l.092-.068c.075-.053.15-.105.226-.156.019-.013.038-.028.06-.04a9.18 9.18 0 01.362-.227c.08-.047.16-.094.241-.139l.11-.058a7.643 7.643 0 01.521-.256l.126-.056a7.509 7.509 0 01.546-.208l.107-.037c.11-.036.22-.069.33-.1l.63-.172c.095-.026.191-.05.287-.072l.097-.02c.062-.014.125-.029.187-.04l.114-.018c.055-.01.11-.02.166-.028.04-.006.08-.01.12-.014.053-.007.105-.014.157-.019l.083-.006c.061-.005.123-.01.184-.013.034-.003.067-.003.101-.004l.16-.006h.11a3.187 3.187 0 01.261.008l.153.01.067.007c.064.006.128.013.192.022l.043.005a5.232 5.232 0 01.281.047l.141.03c.073.016.146.035.218.053l.07.019c.094.026.187.055.278.087l.067.025a4.326 4.326 0 01.449.19l.143.072L11.617.576z"></path></svg> \ No newline at end of file
diff --git a/website/assets/author-can.jpeg b/website/assets/author-can.jpeg
deleted file mode 100644
index 83c47737..00000000
--- a/website/assets/author-can.jpeg
+++ /dev/null
Binary files differ
diff --git a/website/assets/favicon.png b/website/assets/favicon.png
deleted file mode 100644
index a7720d48..00000000
--- a/website/assets/favicon.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/favicon.svg b/website/assets/favicon.svg
deleted file mode 100644
index 8e3f8c42..00000000
--- a/website/assets/favicon.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg role="img" aria-label="Herdr logo" xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="125 125 250 250" preserveAspectRatio="xMidYMid meet">
- <rect width="512" height="512" fill="#d9dad8"/>
- <g fill="#303438" transform="translate(0 512) scale(.1 -.1)" stroke="none">
- <path d="M2794 3710 c-129 -33 -299 -135 -359 -214 -21 -28 -26 -42 -21 -63 9 -38 154 -178 199 -192 32 -11 41 -9 104 23 171 86 354 70 475 -43 150 -138 150 -379 0 -511 -107 -95 -278 -94 -386 2 l-46 40 -11 -29 c-16 -40 -14 -122 4 -164 60 -144 264 -222 452 -174 360 92 559 494 430 868 -36 103 -81 173 -175 267 -71 72 -100 93 -180 132 -52 26 -127 54 -167 62 -96 21 -230 20 -319 -4z M2183 3695 c-116 -32 -221 -108 -273 -199 -17 -28 -30 -54 -30 -58 0 -4 20 1 45 12 66 28 220 68 294 76 64 7 65 7 137 83 40 41 71 77 69 79 -2 2 -21 8 -42 13 -55 12 -140 10 -200 -6z M2212 3388 c-159 -22 -390 -122 -559 -241 -299 -210 -585 -600 -609 -828 -12 -118 40 -251 125 -318 96 -76 178 -98 426 -116 110 -8 224 -21 254 -29 125 -34 230 -115 272 -211 11 -24 24 -81 30 -127 20 -170 65 -271 166 -374 34 -35 63 -65 63 -67 0 -1 -10 -27 -22 -57 -29 -76 -37 -259 -14 -350 42 -170 158 -318 311 -397 44 -23 98 -46 120 -52 22 -6 45 -14 51 -18 5 -5 15 -48 22 -96 6 -48 14 -92 17 -97 4 -6 415 -10 1131 -10 l1124 0 0 1584 0 1585 -55 -19 c-84 -29 -143 -68 -232 -154 l-83 -78 -54 49 c-111 102 -233 151 -391 160 -113 6 -199 -10 -298 -54 l-60 -27 -26 34 c-37 51 -120 134 -127 128 -3 -4 0 -34 7 -67 17 -89 7 -268 -21 -356 -103 -328 -377 -545 -688 -545 -161 0 -273 41 -373 137 -37 35 -66 75 -85 116 -79 173 -8 407 124 407 44 0 68 -14 117 -66 74 -78 167 -82 238 -9 60 62 72 147 33 231 -42 90 -120 130 -238 122 -50 -4 -85 -14 -131 -37 -89 -45 -122 -52 -176 -40 -92 20 -262 163 -302 253 -11 25 -21 45 -22 45 -1 -1 -30 -6 -65 -11z m-256 -505 c115 -88 129 -102 132 -131 2 -18 -2 -40 -9 -49 -7 -8 -69 -55 -138 -105 -103 -73 -130 -88 -151 -83 -35 8 -51 34 -48 74 3 31 12 42 83 92 44 31 80 61 82 66 1 4 -30 31 -69 58 -39 28 -77 56 -85 63 -18 19 -16 72 4 94 32 35 63 23 199 -79z m528 -88 c23 -24 28 -52 14 -82 l-13 -28 -141 -3 c-130 -2 -142 -1 -158 17 -23 26 -24 66 -1 91 16 18 32 20 151 20 105 0 136 -3 148 -15z"/>
- </g>
-</svg>
diff --git a/website/assets/jbm-OFL.txt b/website/assets/jbm-OFL.txt
deleted file mode 100644
index 5ceee002..00000000
--- a/website/assets/jbm-OFL.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-https://openfontlicense.org
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/website/assets/jbm.woff2 b/website/assets/jbm.woff2
deleted file mode 100644
index 059ca4e7..00000000
--- a/website/assets/jbm.woff2
+++ /dev/null
Binary files differ
diff --git a/website/assets/logo.png b/website/assets/logo.png
deleted file mode 100644
index 9c2e60c1..00000000
--- a/website/assets/logo.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/logo.svg b/website/assets/logo.svg
deleted file mode 100644
index 23057315..00000000
--- a/website/assets/logo.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg role="img" aria-label="Herdr logo" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">
- <rect width="512" height="512" fill="#d9dad8"/>
- <g fill="#303438" transform="translate(0 512) scale(.1 -.1)" stroke="none">
- <path d="M2794 3710 c-129 -33 -299 -135 -359 -214 -21 -28 -26 -42 -21 -63 9 -38 154 -178 199 -192 32 -11 41 -9 104 23 171 86 354 70 475 -43 150 -138 150 -379 0 -511 -107 -95 -278 -94 -386 2 l-46 40 -11 -29 c-16 -40 -14 -122 4 -164 60 -144 264 -222 452 -174 360 92 559 494 430 868 -36 103 -81 173 -175 267 -71 72 -100 93 -180 132 -52 26 -127 54 -167 62 -96 21 -230 20 -319 -4z M2183 3695 c-116 -32 -221 -108 -273 -199 -17 -28 -30 -54 -30 -58 0 -4 20 1 45 12 66 28 220 68 294 76 64 7 65 7 137 83 40 41 71 77 69 79 -2 2 -21 8 -42 13 -55 12 -140 10 -200 -6z M2212 3388 c-159 -22 -390 -122 -559 -241 -299 -210 -585 -600 -609 -828 -12 -118 40 -251 125 -318 96 -76 178 -98 426 -116 110 -8 224 -21 254 -29 125 -34 230 -115 272 -211 11 -24 24 -81 30 -127 20 -170 65 -271 166 -374 34 -35 63 -65 63 -67 0 -1 -10 -27 -22 -57 -29 -76 -37 -259 -14 -350 42 -170 158 -318 311 -397 44 -23 98 -46 120 -52 22 -6 45 -14 51 -18 5 -5 15 -48 22 -96 6 -48 14 -92 17 -97 4 -6 415 -10 1131 -10 l1124 0 0 1584 0 1585 -55 -19 c-84 -29 -143 -68 -232 -154 l-83 -78 -54 49 c-111 102 -233 151 -391 160 -113 6 -199 -10 -298 -54 l-60 -27 -26 34 c-37 51 -120 134 -127 128 -3 -4 0 -34 7 -67 17 -89 7 -268 -21 -356 -103 -328 -377 -545 -688 -545 -161 0 -273 41 -373 137 -37 35 -66 75 -85 116 -79 173 -8 407 124 407 44 0 68 -14 117 -66 74 -78 167 -82 238 -9 60 62 72 147 33 231 -42 90 -120 130 -238 122 -50 -4 -85 -14 -131 -37 -89 -45 -122 -52 -176 -40 -92 20 -262 163 -302 253 -11 25 -21 45 -22 45 -1 -1 -30 -6 -65 -11z m-256 -505 c115 -88 129 -102 132 -131 2 -18 -2 -40 -9 -49 -7 -8 -69 -55 -138 -105 -103 -73 -130 -88 -151 -83 -35 8 -51 34 -48 74 3 31 12 42 83 92 44 31 80 61 82 66 1 4 -30 31 -69 58 -39 28 -77 56 -85 63 -18 19 -16 72 4 94 32 35 63 23 199 -79z m528 -88 c23 -24 28 -52 14 -82 l-13 -28 -141 -3 c-130 -2 -142 -1 -158 17 -23 26 -24 66 -1 91 16 18 32 20 151 20 105 0 136 -3 148 -15z"/>
- </g>
-</svg>
diff --git a/website/assets/mobile-agent-session-v2.jpeg b/website/assets/mobile-agent-session-v2.jpeg
deleted file mode 100644
index 1908bcc0..00000000
--- a/website/assets/mobile-agent-session-v2.jpeg
+++ /dev/null
Binary files differ
diff --git a/website/assets/mobile-switch-menu-v2.jpeg b/website/assets/mobile-switch-menu-v2.jpeg
deleted file mode 100644
index 2901668d..00000000
--- a/website/assets/mobile-switch-menu-v2.jpeg
+++ /dev/null
Binary files differ
diff --git a/website/assets/og-blog-coding-agents-runtimes.png b/website/assets/og-blog-coding-agents-runtimes.png
deleted file mode 100644
index a8c1ee2f..00000000
--- a/website/assets/og-blog-coding-agents-runtimes.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/og-blog-frames-v1.png b/website/assets/og-blog-frames-v1.png
deleted file mode 100644
index 9916587f..00000000
--- a/website/assets/og-blog-frames-v1.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/og-blog-live-updates.png b/website/assets/og-blog-live-updates.png
deleted file mode 100644
index 80bccd4b..00000000
--- a/website/assets/og-blog-live-updates.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/og-blog-yc-v1.png b/website/assets/og-blog-yc-v1.png
deleted file mode 100644
index 65817ff2..00000000
--- a/website/assets/og-blog-yc-v1.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/og-card-v8.png b/website/assets/og-card-v8.png
deleted file mode 100644
index d9f85a30..00000000
--- a/website/assets/og-card-v8.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/og-card-v9.png b/website/assets/og-card-v9.png
deleted file mode 100644
index 0a2d8b74..00000000
--- a/website/assets/og-card-v9.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/ram.svg b/website/assets/ram.svg
deleted file mode 100644
index 925e9af7..00000000
--- a/website/assets/ram.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg role="img" aria-label="Herdr" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">
- <g fill="currentColor" transform="translate(0 512) scale(.1 -.1)" stroke="none">
- <path d="M2794 3710 c-129 -33 -299 -135 -359 -214 -21 -28 -26 -42 -21 -63 9 -38 154 -178 199 -192 32 -11 41 -9 104 23 171 86 354 70 475 -43 150 -138 150 -379 0 -511 -107 -95 -278 -94 -386 2 l-46 40 -11 -29 c-16 -40 -14 -122 4 -164 60 -144 264 -222 452 -174 360 92 559 494 430 868 -36 103 -81 173 -175 267 -71 72 -100 93 -180 132 -52 26 -127 54 -167 62 -96 21 -230 20 -319 -4z M2183 3695 c-116 -32 -221 -108 -273 -199 -17 -28 -30 -54 -30 -58 0 -4 20 1 45 12 66 28 220 68 294 76 64 7 65 7 137 83 40 41 71 77 69 79 -2 2 -21 8 -42 13 -55 12 -140 10 -200 -6z M2212 3388 c-159 -22 -390 -122 -559 -241 -299 -210 -585 -600 -609 -828 -12 -118 40 -251 125 -318 96 -76 178 -98 426 -116 110 -8 224 -21 254 -29 125 -34 230 -115 272 -211 11 -24 24 -81 30 -127 20 -170 65 -271 166 -374 34 -35 63 -65 63 -67 0 -1 -10 -27 -22 -57 -29 -76 -37 -259 -14 -350 42 -170 158 -318 311 -397 44 -23 98 -46 120 -52 22 -6 45 -14 51 -18 5 -5 15 -48 22 -96 6 -48 14 -92 17 -97 4 -6 415 -10 1131 -10 l1124 0 0 1584 0 1585 -55 -19 c-84 -29 -143 -68 -232 -154 l-83 -78 -54 49 c-111 102 -233 151 -391 160 -113 6 -199 -10 -298 -54 l-60 -27 -26 34 c-37 51 -120 134 -127 128 -3 -4 0 -34 7 -67 17 -89 7 -268 -21 -356 -103 -328 -377 -545 -688 -545 -161 0 -273 41 -373 137 -37 35 -66 75 -85 116 -79 173 -8 407 124 407 44 0 68 -14 117 -66 74 -78 167 -82 238 -9 60 62 72 147 33 231 -42 90 -120 130 -238 122 -50 -4 -85 -14 -131 -37 -89 -45 -122 -52 -176 -40 -92 20 -262 163 -302 253 -11 25 -21 45 -22 45 -1 -1 -30 -6 -65 -11z m-256 -505 c115 -88 129 -102 132 -131 2 -18 -2 -40 -9 -49 -7 -8 -69 -55 -138 -105 -103 -73 -130 -88 -151 -83 -35 8 -51 34 -48 74 3 31 12 42 83 92 44 31 80 61 82 66 1 4 -30 31 -69 58 -39 28 -77 56 -85 63 -18 19 -16 72 4 94 32 35 63 23 199 -79z m528 -88 c23 -24 28 -52 14 -82 l-13 -28 -141 -3 c-130 -2 -142 -1 -158 17 -23 26 -24 66 -1 91 16 18 32 20 151 20 105 0 136 -3 148 -15z"/>
- </g>
-</svg>
diff --git a/website/assets/releases/v0.6.3/session-navigator.mp4 b/website/assets/releases/v0.6.3/session-navigator.mp4
deleted file mode 100644
index d33d0650..00000000
--- a/website/assets/releases/v0.6.3/session-navigator.mp4
+++ /dev/null
Binary files differ
diff --git a/website/assets/where-do-agents-run-while-you-sleep.png b/website/assets/where-do-agents-run-while-you-sleep.png
deleted file mode 100644
index 45c98ad9..00000000
--- a/website/assets/where-do-agents-run-while-you-sleep.png
+++ /dev/null
Binary files differ
diff --git a/website/assets/yc-logo.svg b/website/assets/yc-logo.svg
deleted file mode 100644
index b502950a..00000000
--- a/website/assets/yc-logo.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
- <g>
- <rect fill="#FB651E" x="0" y="0" width="256" height="256"></rect>
- <path d="M119.373653,144.745813 L75.43296,62.4315733 L95.5144533,62.4315733 L121.36192,114.52416 C121.759575,115.452022 122.2235,116.413008 122.753707,117.407147 C123.283914,118.401285 123.747838,119.428546 124.145493,120.48896 C124.410597,120.886615 124.609422,121.251127 124.741973,121.582507 C124.874525,121.913886 125.007075,122.212123 125.139627,122.477227 C125.802386,123.802744 126.39886,125.095105 126.929067,126.354347 C127.459274,127.613589 127.923198,128.773399 128.320853,129.833813 C129.381268,127.580433 130.541078,125.1614 131.80032,122.57664 C133.059562,119.99188 134.351922,117.307747 135.67744,114.52416 L161.92256,62.4315733 L180.612267,62.4315733 L136.27392,145.739947 L136.27392,198.826667 L119.373653,198.826667 L119.373653,144.745813 Z" fill="#FFFFFF"></path>
- </g>
-</svg>
diff --git a/website/astro.config.mjs b/website/astro.config.mjs
deleted file mode 100644
index b216e6d8..00000000
--- a/website/astro.config.mjs
+++ /dev/null
@@ -1,251 +0,0 @@
-import { defineConfig } from 'astro/config';
-import sitemap from '@astrojs/sitemap';
-import starlight from '@astrojs/starlight';
-import starlightLlmsTxt from 'starlight-llms-txt';
-
-const repoBlob = 'https://github.com/herdrdev/herdr/blob/master/';
-const nonCanonicalDocsPath = /^\/(?:ja\/|zh-cn\/)?docs\/(?:preview|\d+\.\d+\.\d+)(?:\/|$)/;
-
-function rewriteHerdrLinks() {
- const docsLinks = new Map([
- ['README.md', '/docs/'],
- ['./README.md', '/docs/'],
- ['CONFIGURATION.md', '/docs/configuration/'],
- ['./CONFIGURATION.md', '/docs/configuration/'],
- ['INTEGRATIONS.md', '/docs/integrations/'],
- ['./INTEGRATIONS.md', '/docs/integrations/'],
- ['SOCKET_API.md', '/docs/socket-api/'],
- ['./SOCKET_API.md', '/docs/socket-api/'],
- ['SKILL.md', '/docs/agent-skill/'],
- ['./SKILL.md', '/docs/agent-skill/'],
- ]);
-
- return function transform(tree) {
- walk(tree, (node) => {
- if (!node || (node.type !== 'link' && node.type !== 'definition')) return;
- if (typeof node.url !== 'string') return;
-
- const [path, suffix = ''] = node.url.split(/(?=[#?])/);
- const mapped = docsLinks.get(path);
- if (mapped) {
- node.url = `${mapped}${suffix}`;
- return;
- }
-
- const sourcePath = path.startsWith('./') ? path.slice(2) : path;
- if (
- sourcePath.startsWith('src/') ||
- sourcePath.startsWith('scripts/') ||
- sourcePath.startsWith('assets/')
- ) {
- node.url = `${repoBlob}${sourcePath}${suffix}`;
- }
- });
- };
-}
-
-function walk(node, visitor) {
- visitor(node);
- if (!node || !Array.isArray(node.children)) return;
- for (const child of node.children) walk(child, visitor);
-}
-
-export default defineConfig({
- site: 'https://herdr.dev',
- redirects: {
- '/ja': '/ja/docs/',
- '/zh-cn': '/zh-cn/docs/',
- /* /stats/ was public and is linked from elsewhere; the numbers it carried
- now live in the hero strip and the nav count. One key only — Astro
- normalizes the trailing slash and treats both spellings as one route. */
- '/stats': '/',
- },
- integrations: [
- sitemap({
- filter: (page) => !nonCanonicalDocsPath.test(new URL(page).pathname),
- i18n: {
- defaultLocale: 'root',
- locales: { root: 'en', ja: 'ja', 'zh-cn': 'zh-CN' },
- },
- }),
- starlight({
- title: 'herdr',
- description: 'Terminal-native agent runtime and multiplexer.',
- favicon: '/favicon.ico',
- defaultLocale: 'root',
- locales: {
- root: { label: 'English', lang: 'en' },
- ja: { label: '日本語', lang: 'ja' },
- 'zh-cn': { label: '简体中文', lang: 'zh-CN' },
- },
- social: [
- {
- icon: 'github',
- label: 'GitHub',
- href: 'https://github.com/herdrdev/herdr',
- },
- ],
- components: {
- Banner: './src/components/Banner.astro',
- Head: './src/components/Head.astro',
- Header: './src/components/Header.astro',
- Search: './src/components/Search.astro',
- Sidebar: './src/components/Sidebar.astro',
- SiteTitle: './src/components/SiteTitle.astro',
- },
- plugins: [
- starlightLlmsTxt({
- projectName: 'Herdr',
- description: 'Terminal workspace manager and runtime for AI coding agents.',
- details: 'These files document the current stable Herdr release. Preview and archived release documentation are intentionally excluded.',
- exclude: ['docs/preview{,/**}', 'docs/+([0-9]).+([0-9]).+([0-9]){,/**}'],
- optionalLinks: [
- {
- label: 'Agent guide',
- url: 'https://herdr.dev/agent-guide.md',
- description: 'help a human understand, set up, or troubleshoot Herdr',
- },
- ],
- }),
- ],
- customCss: ['./src/styles/starlight.css'],
- head: [
- {
- // Google's favicon crawler rejects icons smaller than 48px
- tag: 'link',
- attrs: { rel: 'icon', type: 'image/png', sizes: '192x192', href: '/assets/favicon.png' },
- },
- { tag: 'link', attrs: { rel: 'apple-touch-icon', href: '/assets/logo.png' } },
- // the brand display face; Starlight owns its own <head>, so the
- // marketing pages' font link doesn't reach docs
- { tag: 'link', attrs: { rel: 'preconnect', href: 'https://fonts.googleapis.com' } },
- {
- tag: 'link',
- attrs: { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: true },
- },
- {
- tag: 'link',
- attrs: {
- rel: 'stylesheet',
- href: 'https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&family=Inter:wght@400;500;600&display=swap',
- },
- },
- {
- // First-visit locale redirect: honors browser language order, then
- // remembers the last locale the reader actually used.
- tag: 'script',
- content: `(function () {
- try {
- var KEY = 'herdr-docs-lang';
- var path = location.pathname;
- var m = path.match(/^\\/(ja|zh-cn)(?=\\/|$)/);
- var current = m ? m[1] : path.indexOf('/docs') === 0 ? 'en' : null;
- if (!current) return;
- if (!localStorage.getItem(KEY) && current === 'en') {
- var langs = navigator.languages && navigator.languages.length ? navigator.languages : [navigator.language || ''];
- var target = null;
- for (var i = 0; i < langs.length && !target; i++) {
- var l = String(langs[i]).toLowerCase();
- if (l === 'ja' || l.indexOf('ja-') === 0) target = 'ja';
- else if (l === 'zh' || l.indexOf('zh-') === 0) target = 'zh-cn';
- else if (l.indexOf('en') === 0) break;
- }
- if (target) {
- localStorage.setItem(KEY, target);
- location.replace('/' + target + path + location.search + location.hash);
- return;
- }
- }
- localStorage.setItem(KEY, current);
- } catch (e) {}
-})();`,
- },
- {
- tag: 'meta',
- attrs: { property: 'og:image', content: 'https://herdr.dev/assets/og-card-v9.png' },
- },
- { tag: 'meta', attrs: { property: 'og:image:width', content: '1200' } },
- { tag: 'meta', attrs: { property: 'og:image:height', content: '630' } },
- {
- tag: 'meta',
- attrs: {
- property: 'og:image:alt',
- content: 'Herdr documentation — run them anywhere, leave them running.',
- },
- },
- {
- tag: 'meta',
- attrs: { name: 'twitter:image', content: 'https://herdr.dev/assets/og-card-v9.png' },
- },
- {
- tag: 'meta',
- attrs: {
- name: 'twitter:image:alt',
- content: 'Herdr documentation — run them anywhere, leave them running.',
- },
- },
- ],
- editLink: {
- baseUrl: 'https://github.com/herdrdev/herdr/edit/master/',
- },
- lastUpdated: true,
- disable404Route: true,
- sidebar: [
- {
- label: 'Start here',
- translations: { ja: 'はじめに', 'zh-CN': '从这里开始' },
- items: [
- { label: 'Overview', translations: { ja: '概要', 'zh-CN': '概览' }, slug: 'docs' },
- { label: 'Install', translations: { ja: 'インストール', 'zh-CN': '安装' }, slug: 'docs/install' },
- { label: 'Quick start', translations: { ja: 'クイックスタート', 'zh-CN': '快速开始' }, slug: 'docs/quick-start' },
- { label: 'Concepts', translations: { ja: 'コンセプト', 'zh-CN': '核心概念' }, slug: 'docs/concepts' },
- { label: 'Keyboard', translations: { ja: 'キーボード', 'zh-CN': '键盘' }, slug: 'docs/keyboard' },
- ],
- },
- {
- label: 'Using Herdr',
- translations: { ja: 'Herdr を使う', 'zh-CN': '使用 Herdr' },
- items: [
- { label: 'How to work with Herdr', translations: { ja: 'Herdr での作業の進め方', 'zh-CN': '使用 Herdr 的工作方式' }, slug: 'docs/how-to-work' },
- { label: 'Agents', translations: { ja: 'エージェント', 'zh-CN': '智能体' }, slug: 'docs/agents' },
- { label: 'Agent automation', translations: { ja: 'エージェント自動化', 'zh-CN': '智能体自动化' }, slug: 'docs/agent-automation' },
- { label: 'Session state and restore', translations: { ja: 'セッション状態と復元', 'zh-CN': '会话状态与恢复' }, slug: 'docs/session-state' },
- { label: 'Persistence and remote access', translations: { ja: '永続化とリモートアクセス', 'zh-CN': '持久化与远程访问' }, slug: 'docs/persistence-remote' },
- ],
- },
- {
- label: 'Configure',
- translations: { ja: '設定する', 'zh-CN': '配置' },
- items: [
- { label: 'Configuration', translations: { ja: '設定', 'zh-CN': '配置指南' }, slug: 'docs/configuration' },
- { label: 'Config reference', translations: { ja: '設定リファレンス', 'zh-CN': '配置参考' }, slug: 'docs/config-reference' },
- { label: 'Plugins', translations: { ja: 'プラグイン', 'zh-CN': '插件' }, slug: 'docs/plugins' },
- { label: 'Marketplace', translations: { ja: 'マーケットプレイス', 'zh-CN': '插件市场' }, slug: 'docs/marketplace' },
- ],
- },
- {
- label: 'Reference',
- translations: { ja: 'リファレンス', 'zh-CN': '参考' },
- items: [
- { label: 'CLI reference', translations: { ja: 'CLI リファレンス', 'zh-CN': 'CLI 参考' }, slug: 'docs/cli-reference' },
- { label: 'Socket API', translations: { ja: 'ソケット API', 'zh-CN': 'Socket API' }, slug: 'docs/socket-api' },
- { label: 'Integrations', translations: { ja: 'インテグレーション', 'zh-CN': '集成' }, slug: 'docs/integrations' },
- { label: 'Agent skill file', translations: { ja: 'エージェントスキルファイル', 'zh-CN': '智能体技能文件' }, slug: 'docs/agent-skill' },
- { label: 'Windows support', translations: { ja: 'Windows サポート', 'zh-CN': 'Windows 支持' }, slug: 'docs/windows-beta' },
- ],
- },
- {
- label: 'Help',
- translations: { ja: 'ヘルプ', 'zh-CN': '帮助' },
- items: [
- { label: 'Troubleshooting', translations: { ja: 'トラブルシューティング', 'zh-CN': '故障排除' }, slug: 'docs/troubleshooting' },
- { label: 'Preview docs', translations: { ja: 'プレビュー版ドキュメント', 'zh-CN': '预览版文档' }, slug: 'docs/preview' },
- ],
- },
- ],
- }),
- ],
- markdown: {
- remarkPlugins: [rewriteHerdrLinks],
- },
-});
diff --git a/website/bun.lock b/website/bun.lock
deleted file mode 100644
index 28bac73d..00000000
--- a/website/bun.lock
+++ /dev/null
@@ -1,994 +0,0 @@
-{
- "lockfileVersion": 1,
- "configVersion": 1,
- "workspaces": {
- "": {
- "name": "herdr-website",
- "dependencies": {
- "@astrojs/sitemap": "^3.7.2",
- "@astrojs/starlight": "^0.36.0",
- "astro": "^5.0.0",
- "starlight-llms-txt": "0.6.1",
- },
- },
- },
- "packages": {
- "@astrojs/compiler": ["@astrojs/compiler@2.13.1", "", {}, "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="],
-
- "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.6", "", {}, "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q=="],
-
- "@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.11", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.6", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ=="],
-
- "@astrojs/mdx": ["@astrojs/mdx@4.3.14", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.11", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "piccolore": "^0.1.3", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-FBrqJQORVm+rkRa2TS5CjU9PBA6hkhrwLVBSS9A77gN2+iehvjq1w6yya/d0YKC7osiVorKkr3Qd9wNbl0ZkGA=="],
-
- "@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
-
- "@astrojs/sitemap": ["@astrojs/sitemap@3.7.2", "", { "dependencies": { "sitemap": "^9.0.0", "stream-replace-string": "^2.0.0", "zod": "^4.3.6" } }, "sha512-PqkzkcZTb5ICiyIR8VoKbIAP/laNRXi5tw616N1Ckk+40oNB8Can1AzVV56lrbC5GKSZFCyJYUVYqVivMisvpA=="],
-
- "@astrojs/starlight": ["@astrojs/starlight@0.36.3", "", { "dependencies": { "@astrojs/markdown-remark": "^6.3.1", "@astrojs/mdx": "^4.2.3", "@astrojs/sitemap": "^3.3.0", "@pagefind/default-ui": "^1.3.0", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", "@types/mdast": "^4.0.4", "astro-expressive-code": "^0.41.1", "bcp-47": "^2.1.0", "hast-util-from-html": "^2.0.1", "hast-util-select": "^6.0.2", "hast-util-to-string": "^3.0.0", "hastscript": "^9.0.0", "i18next": "^23.11.5", "js-yaml": "^4.1.0", "klona": "^2.0.6", "mdast-util-directive": "^3.0.0", "mdast-util-to-markdown": "^2.1.0", "mdast-util-to-string": "^4.0.0", "pagefind": "^1.3.0", "rehype": "^13.0.1", "rehype-format": "^5.0.0", "remark-directive": "^3.0.0", "ultrahtml": "^1.6.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "vfile": "^6.0.2" }, "peerDependencies": { "astro": "^5.5.0" } }, "sha512-5cm4QVQHUP6ZE52O43TtUpsTvLKdZa9XEs4l3suzuY7Ymsbz4ojtoL9NhistbMqM+/qk6fm6SmxbOL6hQ/LfNA=="],
-
- "@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="],
-
- "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
-
- "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
-
- "@babel/parser": ["@babel/parser@7.29.3", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA=="],
-
- "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="],
-
- "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
-
- "@capsizecss/unpack": ["@capsizecss/unpack@4.0.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA=="],
-
- "@ctrl/tinycolor": ["@ctrl/tinycolor@4.2.0", "", {}, "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A=="],
-
- "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
-
- "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
-
- "@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="],
-
- "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="],
-
- "@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="],
-
- "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="],
-
- "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="],
-
- "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="],
-
- "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="],
-
- "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="],
-
- "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="],
-
- "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="],
-
- "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="],
-
- "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="],
-
- "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="],
-
- "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="],
-
- "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="],
-
- "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="],
-
- "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="],
-
- "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="],
-
- "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="],
-
- "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="],
-
- "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="],
-
- "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="],
-
- "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="],
-
- "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="],
-
- "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
-
- "@expressive-code/core": ["@expressive-code/core@0.41.7", "", { "dependencies": { "@ctrl/tinycolor": "^4.0.4", "hast-util-select": "^6.0.2", "hast-util-to-html": "^9.0.1", "hast-util-to-text": "^4.0.1", "hastscript": "^9.0.0", "postcss": "^8.4.38", "postcss-nested": "^6.0.1", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1" } }, "sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg=="],
-
- "@expressive-code/plugin-frames": ["@expressive-code/plugin-frames@0.41.7", "", { "dependencies": { "@expressive-code/core": "^0.41.7" } }, "sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA=="],
-
- "@expressive-code/plugin-shiki": ["@expressive-code/plugin-shiki@0.41.7", "", { "dependencies": { "@expressive-code/core": "^0.41.7", "shiki": "^3.2.2" } }, "sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ=="],
-
- "@expressive-code/plugin-text-markers": ["@expressive-code/plugin-text-markers@0.41.7", "", { "dependencies": { "@expressive-code/core": "^0.41.7" } }, "sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw=="],
-
- "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="],
-
- "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
-
- "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="],
-
- "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="],
-
- "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="],
-
- "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="],
-
- "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="],
-
- "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="],
-
- "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="],
-
- "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="],
-
- "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="],
-
- "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="],
-
- "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="],
-
- "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="],
-
- "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="],
-
- "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="],
-
- "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="],
-
- "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="],
-
- "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="],
-
- "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="],
-
- "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="],
-
- "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="],
-
- "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="],
-
- "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="],
-
- "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
-
- "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
-
- "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="],
-
- "@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="],
-
- "@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ=="],
-
- "@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw=="],
-
- "@pagefind/default-ui": ["@pagefind/default-ui@1.5.2", "", {}, "sha512-pm1LMnQg8N2B3n2TnjKlhaFihpz6zTiA4HiGQ6/slKO/+8K9CAU5kcjdSSPgpuk1PMuuN4hxLipUIifnrkl3Sg=="],
-
- "@pagefind/freebsd-x64": ["@pagefind/freebsd-x64@1.5.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA=="],
-
- "@pagefind/linux-arm64": ["@pagefind/linux-arm64@1.5.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw=="],
-
- "@pagefind/linux-x64": ["@pagefind/linux-x64@1.5.2", "", { "os": "linux", "cpu": "x64" }, "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA=="],
-
- "@pagefind/windows-arm64": ["@pagefind/windows-arm64@1.5.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g=="],
-
- "@pagefind/windows-x64": ["@pagefind/windows-x64@1.5.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg=="],
-
- "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
-
- "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.4", "", { "os": "android", "cpu": "arm" }, "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ=="],
-
- "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.4", "", { "os": "android", "cpu": "arm64" }, "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw=="],
-
- "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA=="],
-
- "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg=="],
-
- "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g=="],
-
- "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw=="],
-
- "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.4", "", { "os": "linux", "cpu": "arm" }, "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA=="],
-
- "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.4", "", { "os": "linux", "cpu": "arm" }, "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w=="],
-
- "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg=="],
-
- "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A=="],
-
- "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ=="],
-
- "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw=="],
-
- "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg=="],
-
- "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A=="],
-
- "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA=="],
-
- "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw=="],
-
- "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ=="],
-
- "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.4", "", { "os": "linux", "cpu": "x64" }, "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ=="],
-
- "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg=="],
-
- "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA=="],
-
- "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.4", "", { "os": "none", "cpu": "arm64" }, "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg=="],
-
- "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw=="],
-
- "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA=="],
-
- "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.4", "", { "os": "win32", "cpu": "x64" }, "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw=="],
-
- "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.4", "", { "os": "win32", "cpu": "x64" }, "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw=="],
-
- "@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],
-
- "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],
-
- "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="],
-
- "@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="],
-
- "@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="],
-
- "@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],
-
- "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
-
- "@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="],
-
- "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="],
-
- "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="],
-
- "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="],
-
- "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="],
-
- "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
-
- "@types/mdx": ["@types/mdx@2.0.13", "", {}, "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw=="],
-
- "@types/micromatch": ["@types/micromatch@4.0.10", "", { "dependencies": { "@types/braces": "*" } }, "sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ=="],
-
- "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
-
- "@types/nlcst": ["@types/nlcst@2.0.3", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="],
-
- "@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="],
-
- "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="],
-
- "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "@ungap/structured-clone": ["@ungap/structured-clone@1.3.1", "", {}, "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ=="],
-
- "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
-
- "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
-
- "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
-
- "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
-
- "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
-
- "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
-
- "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="],
-
- "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
-
- "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
-
- "array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="],
-
- "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
-
- "astro": ["astro@5.18.1", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.6", "@astrojs/markdown-remark": "6.3.11", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^4.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.1.1", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.6.2", "diff": "^8.0.3", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.27.3", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.4.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", "magicast": "^0.5.1", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.7.3", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.4", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.25.1", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-m4VWilWZ+Xt6NPoYzC4CgGZim/zQUO7WFL0RHCH0AiEavF1153iC3+me2atDvXpf/yX4PyGUeD8wZLq1cirT3g=="],
-
- "astro-expressive-code": ["astro-expressive-code@0.41.7", "", { "dependencies": { "rehype-expressive-code": "^0.41.7" }, "peerDependencies": { "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta" } }, "sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ=="],
-
- "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
-
- "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
-
- "base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="],
-
- "bcp-47": ["bcp-47@2.1.0", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w=="],
-
- "bcp-47-match": ["bcp-47-match@2.0.3", "", {}, "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ=="],
-
- "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
-
- "boxen": ["boxen@8.0.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", "cli-boxes": "^3.0.0", "string-width": "^7.2.0", "type-fest": "^4.21.0", "widest-line": "^5.0.0", "wrap-ansi": "^9.0.0" } }, "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw=="],
-
- "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
-
- "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
-
- "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
-
- "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
-
- "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
-
- "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="],
-
- "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
-
- "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
-
- "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
-
- "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="],
-
- "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
-
- "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
-
- "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="],
-
- "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
-
- "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
-
- "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="],
-
- "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
-
- "cookie-es": ["cookie-es@1.2.3", "", {}, "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw=="],
-
- "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="],
-
- "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
-
- "css-selector-parser": ["css-selector-parser@3.3.0", "", {}, "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g=="],
-
- "css-tree": ["css-tree@3.2.1", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA=="],
-
- "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="],
-
- "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
-
- "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="],
-
- "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
-
- "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="],
-
- "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
-
- "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
-
- "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
-
- "deterministic-object-hash": ["deterministic-object-hash@2.0.2", "", { "dependencies": { "base-64": "^1.0.0" } }, "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ=="],
-
- "devalue": ["devalue@5.8.1", "", {}, "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw=="],
-
- "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
-
- "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="],
-
- "direction": ["direction@2.0.1", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="],
-
- "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
-
- "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
-
- "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
-
- "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
-
- "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
-
- "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="],
-
- "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
-
- "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
-
- "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
-
- "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="],
-
- "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="],
-
- "esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="],
-
- "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
-
- "estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="],
-
- "estree-util-build-jsx": ["estree-util-build-jsx@3.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-walker": "^3.0.0" } }, "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ=="],
-
- "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="],
-
- "estree-util-scope": ["estree-util-scope@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0" } }, "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ=="],
-
- "estree-util-to-js": ["estree-util-to-js@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "astring": "^1.8.0", "source-map": "^0.7.0" } }, "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg=="],
-
- "estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="],
-
- "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
-
- "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
-
- "expressive-code": ["expressive-code@0.41.7", "", { "dependencies": { "@expressive-code/core": "^0.41.7", "@expressive-code/plugin-frames": "^0.41.7", "@expressive-code/plugin-shiki": "^0.41.7", "@expressive-code/plugin-text-markers": "^0.41.7" } }, "sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA=="],
-
- "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
-
- "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
-
- "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
-
- "flattie": ["flattie@1.1.1", "", {}, "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="],
-
- "fontace": ["fontace@0.4.1", "", { "dependencies": { "fontkitten": "^1.0.2" } }, "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw=="],
-
- "fontkitten": ["fontkitten@1.0.3", "", { "dependencies": { "tiny-inflate": "^1.0.3" } }, "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw=="],
-
- "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
-
- "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
-
- "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
-
- "h3": ["h3@1.15.11", "", { "dependencies": { "cookie-es": "^1.2.3", "crossws": "^0.3.5", "defu": "^6.1.6", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg=="],
-
- "hast-util-embedded": ["hast-util-embedded@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-is-element": "^3.0.0" } }, "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA=="],
-
- "hast-util-format": ["hast-util-format@1.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-minify-whitespace": "^1.0.0", "hast-util-phrasing": "^3.0.0", "hast-util-whitespace": "^3.0.0", "html-whitespace-sensitive-tag-names": "^3.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA=="],
-
- "hast-util-from-html": ["hast-util-from-html@2.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", "hast-util-from-parse5": "^8.0.0", "parse5": "^7.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw=="],
-
- "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="],
-
- "hast-util-has-property": ["hast-util-has-property@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA=="],
-
- "hast-util-is-body-ok-link": ["hast-util-is-body-ok-link@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ=="],
-
- "hast-util-is-element": ["hast-util-is-element@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g=="],
-
- "hast-util-minify-whitespace": ["hast-util-minify-whitespace@1.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-is-element": "^3.0.0", "hast-util-whitespace": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw=="],
-
- "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="],
-
- "hast-util-phrasing": ["hast-util-phrasing@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-has-property": "^3.0.0", "hast-util-is-body-ok-link": "^3.0.0", "hast-util-is-element": "^3.0.0" } }, "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ=="],
-
- "hast-util-raw": ["hast-util-raw@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-from-parse5": "^8.0.0", "hast-util-to-parse5": "^8.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "parse5": "^7.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw=="],
-
- "hast-util-select": ["hast-util-select@6.0.4", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "bcp-47-match": "^2.0.0", "comma-separated-tokens": "^2.0.0", "css-selector-parser": "^3.0.0", "devlop": "^1.0.0", "direction": "^2.0.0", "hast-util-has-property": "^3.0.0", "hast-util-to-string": "^3.0.0", "hast-util-whitespace": "^3.0.0", "nth-check": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw=="],
-
- "hast-util-to-estree": ["hast-util-to-estree@3.1.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-attach-comments": "^3.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w=="],
-
- "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="],
-
- "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="],
-
- "hast-util-to-mdast": ["hast-util-to-mdast@10.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-phrasing": "^3.0.0", "hast-util-to-html": "^9.0.0", "hast-util-to-text": "^4.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "mdast-util-to-string": "^4.0.0", "rehype-minify-whitespace": "^6.0.0", "trim-trailing-lines": "^2.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ=="],
-
- "hast-util-to-parse5": ["hast-util-to-parse5@8.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA=="],
-
- "hast-util-to-string": ["hast-util-to-string@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A=="],
-
- "hast-util-to-text": ["hast-util-to-text@4.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "hast-util-is-element": "^3.0.0", "unist-util-find-after": "^5.0.0" } }, "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A=="],
-
- "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="],
-
- "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="],
-
- "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="],
-
- "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="],
-
- "html-whitespace-sensitive-tag-names": ["html-whitespace-sensitive-tag-names@3.0.1", "", {}, "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA=="],
-
- "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
-
- "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="],
-
- "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="],
-
- "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
-
- "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
-
- "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
-
- "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="],
-
- "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="],
-
- "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
-
- "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
-
- "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
-
- "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
-
- "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
-
- "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],
-
- "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
-
- "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
-
- "klona": ["klona@2.0.6", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="],
-
- "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
-
- "lru-cache": ["lru-cache@11.3.6", "", {}, "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A=="],
-
- "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
-
- "magicast": ["magicast@0.5.3", "", { "dependencies": { "@babel/parser": "^7.29.3", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw=="],
-
- "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="],
-
- "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
-
- "mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="],
-
- "mdast-util-directive": ["mdast-util-directive@3.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q=="],
-
- "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="],
-
- "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="],
-
- "mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="],
-
- "mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="],
-
- "mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="],
-
- "mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="],
-
- "mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="],
-
- "mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="],
-
- "mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="],
-
- "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
-
- "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="],
-
- "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="],
-
- "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="],
-
- "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="],
-
- "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="],
-
- "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="],
-
- "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="],
-
- "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
-
- "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
-
- "micromark-extension-directive": ["micromark-extension-directive@3.0.2", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "parse-entities": "^4.0.0" } }, "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA=="],
-
- "micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="],
-
- "micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="],
-
- "micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="],
-
- "micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="],
-
- "micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="],
-
- "micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="],
-
- "micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="],
-
- "micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="],
-
- "micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="],
-
- "micromark-extension-mdx-md": ["micromark-extension-mdx-md@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ=="],
-
- "micromark-extension-mdxjs": ["micromark-extension-mdxjs@3.0.0", "", { "dependencies": { "acorn": "^8.0.0", "acorn-jsx": "^5.0.0", "micromark-extension-mdx-expression": "^3.0.0", "micromark-extension-mdx-jsx": "^3.0.0", "micromark-extension-mdx-md": "^2.0.0", "micromark-extension-mdxjs-esm": "^3.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ=="],
-
- "micromark-extension-mdxjs-esm": ["micromark-extension-mdxjs-esm@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A=="],
-
- "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="],
-
- "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="],
-
- "micromark-factory-mdx-expression": ["micromark-factory-mdx-expression@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ=="],
-
- "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="],
-
- "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="],
-
- "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="],
-
- "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="],
-
- "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="],
-
- "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="],
-
- "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="],
-
- "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="],
-
- "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="],
-
- "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="],
-
- "micromark-util-events-to-acorn": ["micromark-util-events-to-acorn@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg=="],
-
- "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="],
-
- "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="],
-
- "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="],
-
- "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="],
-
- "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="],
-
- "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="],
-
- "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
-
- "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
-
- "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
-
- "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
-
- "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="],
-
- "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="],
-
- "nlcst-to-string": ["nlcst-to-string@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0" } }, "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA=="],
-
- "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
-
- "node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
-
- "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
-
- "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
-
- "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
-
- "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
-
- "oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="],
-
- "oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "^0.12.2", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="],
-
- "p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="],
-
- "p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="],
-
- "p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="],
-
- "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="],
-
- "pagefind": ["pagefind@1.5.2", "", { "optionalDependencies": { "@pagefind/darwin-arm64": "1.5.2", "@pagefind/darwin-x64": "1.5.2", "@pagefind/freebsd-x64": "1.5.2", "@pagefind/linux-arm64": "1.5.2", "@pagefind/linux-x64": "1.5.2", "@pagefind/windows-arm64": "1.5.2", "@pagefind/windows-x64": "1.5.2" }, "bin": { "pagefind": "lib/runner/bin.cjs" } }, "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q=="],
-
- "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],
-
- "parse-latin": ["parse-latin@7.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "@types/unist": "^3.0.0", "nlcst-to-string": "^4.0.0", "unist-util-modify-children": "^4.0.0", "unist-util-visit-children": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ=="],
-
- "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
-
- "piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="],
-
- "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
-
- "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
-
- "postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="],
-
- "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="],
-
- "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
-
- "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
-
- "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
-
- "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
-
- "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
-
- "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
-
- "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="],
-
- "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="],
-
- "recma-parse": ["recma-parse@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "esast-util-from-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ=="],
-
- "recma-stringify": ["recma-stringify@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-to-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g=="],
-
- "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="],
-
- "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="],
-
- "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="],
-
- "rehype": ["rehype@13.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "rehype-parse": "^9.0.0", "rehype-stringify": "^10.0.0", "unified": "^11.0.0" } }, "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A=="],
-
- "rehype-expressive-code": ["rehype-expressive-code@0.41.7", "", { "dependencies": { "expressive-code": "^0.41.7" } }, "sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ=="],
-
- "rehype-format": ["rehype-format@5.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-format": "^1.0.0" } }, "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ=="],
-
- "rehype-minify-whitespace": ["rehype-minify-whitespace@6.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-minify-whitespace": "^1.0.0" } }, "sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw=="],
-
- "rehype-parse": ["rehype-parse@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-html": "^2.0.0", "unified": "^11.0.0" } }, "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag=="],
-
- "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="],
-
- "rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="],
-
- "rehype-remark": ["rehype-remark@10.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "hast-util-to-mdast": "^10.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ=="],
-
- "rehype-stringify": ["rehype-stringify@10.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-html": "^9.0.0", "unified": "^11.0.0" } }, "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA=="],
-
- "remark-directive": ["remark-directive@3.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-directive": "^3.0.0", "micromark-extension-directive": "^3.0.0", "unified": "^11.0.0" } }, "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A=="],
-
- "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="],
-
- "remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="],
-
- "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="],
-
- "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="],
-
- "remark-smartypants": ["remark-smartypants@3.0.2", "", { "dependencies": { "retext": "^9.0.0", "retext-smartypants": "^6.0.0", "unified": "^11.0.4", "unist-util-visit": "^5.0.0" } }, "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA=="],
-
- "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
-
- "retext": ["retext@9.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "retext-latin": "^4.0.0", "retext-stringify": "^4.0.0", "unified": "^11.0.0" } }, "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA=="],
-
- "retext-latin": ["retext-latin@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "parse-latin": "^7.0.0", "unified": "^11.0.0" } }, "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA=="],
-
- "retext-smartypants": ["retext-smartypants@6.2.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ=="],
-
- "retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="],
-
- "rollup": ["rollup@4.60.4", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.4", "@rollup/rollup-android-arm64": "4.60.4", "@rollup/rollup-darwin-arm64": "4.60.4", "@rollup/rollup-darwin-x64": "4.60.4", "@rollup/rollup-freebsd-arm64": "4.60.4", "@rollup/rollup-freebsd-x64": "4.60.4", "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", "@rollup/rollup-linux-arm-musleabihf": "4.60.4", "@rollup/rollup-linux-arm64-gnu": "4.60.4", "@rollup/rollup-linux-arm64-musl": "4.60.4", "@rollup/rollup-linux-loong64-gnu": "4.60.4", "@rollup/rollup-linux-loong64-musl": "4.60.4", "@rollup/rollup-linux-ppc64-gnu": "4.60.4", "@rollup/rollup-linux-ppc64-musl": "4.60.4", "@rollup/rollup-linux-riscv64-gnu": "4.60.4", "@rollup/rollup-linux-riscv64-musl": "4.60.4", "@rollup/rollup-linux-s390x-gnu": "4.60.4", "@rollup/rollup-linux-x64-gnu": "4.60.4", "@rollup/rollup-linux-x64-musl": "4.60.4", "@rollup/rollup-openbsd-x64": "4.60.4", "@rollup/rollup-openharmony-arm64": "4.60.4", "@rollup/rollup-win32-arm64-msvc": "4.60.4", "@rollup/rollup-win32-ia32-msvc": "4.60.4", "@rollup/rollup-win32-x64-gnu": "4.60.4", "@rollup/rollup-win32-x64-msvc": "4.60.4", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g=="],
-
- "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
-
- "semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="],
-
- "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
-
- "shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
-
- "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
-
- "sitemap": ["sitemap@9.0.1", "", { "dependencies": { "@types/node": "^24.9.2", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { "sitemap": "dist/esm/cli.js" } }, "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ=="],
-
- "smol-toml": ["smol-toml@1.6.1", "", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="],
-
- "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
-
- "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
-
- "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
-
- "starlight-llms-txt": ["starlight-llms-txt@0.6.1", "", { "dependencies": { "@astrojs/mdx": "^4.0.5", "@types/hast": "^3.0.4", "@types/micromatch": "^4.0.9", "github-slugger": "^2.0.0", "hast-util-select": "^6.0.3", "micromatch": "^4.0.8", "rehype-parse": "^9.0.1", "rehype-remark": "^10.0.0", "remark-gfm": "^4.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.5", "unist-util-remove": "^4.0.0" }, "peerDependencies": { "@astrojs/starlight": ">=0.31", "astro": "^5.15.9" } }, "sha512-V0XEj92hrWHCDOu2SiDbgPviKnlB/O4Fqh9yeDxjV+udw9y+mSQ+4Obhlj6UUhjn6gfoj0V7dPLM0Dhbd6j1NA=="],
-
- "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="],
-
- "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
-
- "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
-
- "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
-
- "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
-
- "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
-
- "svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="],
-
- "tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
-
- "tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="],
-
- "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
-
- "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
-
- "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
-
- "trim-trailing-lines": ["trim-trailing-lines@2.1.0", "", {}, "sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg=="],
-
- "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
-
- "tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="],
-
- "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
-
- "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
-
- "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
-
- "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="],
-
- "ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="],
-
- "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
-
- "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
- "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
- "unifont": ["unifont@0.7.4", "", { "dependencies": { "css-tree": "^3.1.0", "ofetch": "^1.5.1", "ohash": "^2.0.11" } }, "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg=="],
-
- "unist-util-find-after": ["unist-util-find-after@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ=="],
-
- "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
-
- "unist-util-modify-children": ["unist-util-modify-children@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "array-iterate": "^2.0.0" } }, "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw=="],
-
- "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="],
-
- "unist-util-position-from-estree": ["unist-util-position-from-estree@2.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ=="],
-
- "unist-util-remove": ["unist-util-remove@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg=="],
-
- "unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="],
-
- "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
-
- "unist-util-visit-children": ["unist-util-visit-children@3.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA=="],
-
- "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
-
- "unstorage": ["unstorage@1.17.5", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.10", "lru-cache": "^11.2.7", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg=="],
-
- "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
-
- "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
-
- "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="],
-
- "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
-
- "vite": ["vite@6.4.2", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ=="],
-
- "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="],
-
- "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
-
- "which-pm-runs": ["which-pm-runs@1.1.0", "", {}, "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="],
-
- "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="],
-
- "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
-
- "xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="],
-
- "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
-
- "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="],
-
- "yocto-spinner": ["yocto-spinner@0.2.3", "", { "dependencies": { "yoctocolors": "^2.1.1" } }, "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ=="],
-
- "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="],
-
- "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="],
-
- "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
-
- "zod-to-ts": ["zod-to-ts@1.2.0", "", { "peerDependencies": { "typescript": "^4.9.4 || ^5.0.2", "zod": "^3" } }, "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA=="],
-
- "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
-
- "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
-
- "ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
-
- "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
-
- "astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
-
- "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
-
- "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
-
- "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
-
- "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
-
- "rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
-
- "vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
-
- "zod-to-ts/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
-
- "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
-
- "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
-
- "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
-
- "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
-
- "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
-
- "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
-
- "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
-
- "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
-
- "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
-
- "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
-
- "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
-
- "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
-
- "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
-
- "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
-
- "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
-
- "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
-
- "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
-
- "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
-
- "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
-
- "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
-
- "vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
-
- "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
-
- "vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
-
- "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
-
- "vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
-
- "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
-
- "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
-
- "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
-
- "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
-
- "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
- }
-}
diff --git a/website/css/og-card.css b/website/css/og-card.css
deleted file mode 100644
index 8bb852d7..00000000
--- a/website/css/og-card.css
+++ /dev/null
@@ -1,102 +0,0 @@
-/* ──────────────────────────────────────────────────────────────
- Shared chassis for the OG cards.
-
- Cards are authored as real 1200x630 HTML so they use the same fonts
- and palette as the site and can be regenerated with a screenshot
- instead of a design session. Tokens mirror site.css's ink ground —
- duplicated deliberately, because a card is a frozen artifact and
- must not change shape when the site's CSS does.
- ────────────────────────────────────────────────────────────── */
-
-@font-face {
- font-family: "JetBrains Mono";
- font-style: normal;
- font-weight: 400 700;
- font-display: block;
- src: url("/assets/jbm.woff2?v=2") format("woff2");
-}
-
-:root {
- --bg: #0c0c12;
- --panel: #111119;
- --mass: #1a1a24;
- --ink: #e9e6f2;
- --dim: #a29db8;
- --faint: #736e8a;
- --line: #1a1a24;
- --line2: #2a2839;
- --spot: #cba6f7;
- --run: #5fae74;
- --wait: #d3a027;
- --idle: #5a615c;
- --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
- --disp: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;
-}
-
-* { box-sizing: border-box; }
-/* On a card page the document IS the card, so a full-page capture is the
- finished asset at exactly 1200x630 whatever the window size. Scoped to
- .og so the comparison viewer, which loads this same file for the tokens,
- isn't clamped to card dimensions. */
-html.og, body.og {
- margin: 0; padding: 0; background: var(--bg);
- width: 1200px; height: 630px; overflow: hidden;
-}
-
-.card {
- position: relative;
- width: 1200px;
- height: 630px;
- overflow: hidden;
- background: var(--bg);
- color: var(--ink);
- font-family: var(--mono);
- -webkit-font-smoothing: antialiased;
- background-image:
- linear-gradient(var(--line) 1px, transparent 1px),
- linear-gradient(90deg, var(--line) 1px, transparent 1px);
- background-size: 60px 60px;
-}
-
-/* the ram as mass, bleeding off the right edge */
-.card .ram {
- background: currentColor;
- -webkit-mask: url("/assets/ram.svg") center/contain no-repeat;
- mask: url("/assets/ram.svg") center/contain no-repeat;
- display: block;
-}
-.card .mass {
- position: absolute;
- right: -110px;
- top: 50%;
- transform: translateY(-50%);
- width: 620px;
- height: 620px;
- color: var(--mass);
- z-index: 0;
-}
-.card .in { position: relative; z-index: 1; height: 100%; }
-
-/* lockup */
-.lockup { display: flex; align-items: center; gap: 14px; }
-.lockup .ram { width: 38px; height: 38px; color: var(--ink); }
-.lockup b {
- font-family: var(--disp);
- font-weight: 900;
- font-size: 34px;
- letter-spacing: -0.045em;
-}
-
-.eyebrow {
- display: flex;
- align-items: center;
- gap: 18px;
- color: var(--spot);
- font-size: 19px;
- letter-spacing: 0.3em;
- text-transform: uppercase;
-}
-.eyebrow s { width: 56px; height: 2px; background: var(--spot); text-decoration: none; }
-
-/* keep the safe area generous: some surfaces crop toward square */
-.pad { padding: 54px 62px; }
diff --git a/website/css/site.css b/website/css/site.css
deleted file mode 100644
index 5654fc48..00000000
--- a/website/css/site.css
+++ /dev/null
@@ -1,828 +0,0 @@
-/* ──────────────────────────────────────────────────────────────
- site.css — herdr.dev chassis. Loaded after style.css, which is
- kept only for the session mock (.herdr-ui-mock) and its tokens.
- Ink is the default ground; paper is shared with the docs via
- Starlight's `starlight-theme` key.
- ────────────────────────────────────────────────────────────── */
-
-html,
-html[data-mode="ink"] {
- --bg: #17171a; --panel: #1e1e22; --mass: #26262b;
- --ink: #eae8ee; --dim: #cdccd2; --faint: #b0afb6; --faint2: #908f96;
- --line: #26262b; --line2: #35353d;
- --spot: #cba6f7; --spot-ink: #17171a;
- --grid: #202024;
-}
-html[data-mode="paper"] {
- --st-done: #2aa198;
- --bg: #efece5; --panel: #e7e3da; --mass: #ddd8cc;
- --ink: #15140f; --dim: #55534a; --faint: #86826f; --faint2: #928e79;
- --line: #e2ded4; --line2: #cbc5b6;
- --spot: #8839ef; --spot-ink: #fff;
- --grid: #e4e0d6;
-}
-:root {
- --run: #5fae74; --wait: #d3a027; --idle: #5a615c; --done: #6f6a86;
- /* agent state colours alias the style.css tokens so the legend, the
- plate and the app stay in step */
- --st-blocked: var(--red);
- --st-working: var(--yellow);
- --st-idle: var(--green);
- /* style.css has no teal token to alias, so done is set per ground */
- --st-done: #94e2d5;
- --disp: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;
- --body: "Inter", system-ui, -apple-system, "Segoe UI", Helvetica, sans-serif;
- --gut: 34px;
-}
-
-body.site .mock-agent.done > span,
-body.site .mock-agent.done small { color: var(--st-done); }
-
-html[data-palette] {
- --accent: var(--spot);
- --term-tab-active-bg: var(--spot);
- --term-tab-active-text: var(--spot-ink);
- --term-prompt: var(--spot);
- --term-blue: var(--spot);
-}
-
-/* bridge style.css's legacy token names onto the neutral scale; scoped to
- this page so the mock keeps its own --radius-* */
-body.site .plugins-page {
- --bg-elevated: var(--panel);
- --ink-soft: var(--dim);
- --muted: var(--faint);
- --muted-2: var(--faint2);
- --line-strong: var(--line2);
- --accent-soft: color-mix(in srgb, var(--spot) 8%, transparent);
- --radius-sm: 0; --radius-md: 0; --radius-lg: 0;
-}
-
-body.site {
- margin: 0; background: var(--bg); color: var(--ink);
- font-family: var(--body); font-size: 14.5px; line-height: 1.65;
- /* no `antialiased`: grayscale smoothing thins light-on-dark glyphs on macOS */
- background-image:
- linear-gradient(var(--grid) 1px, transparent 1px),
- linear-gradient(90deg, var(--grid) 1px, transparent 1px);
- background-size: 72px 72px;
- overflow-x: clip;
- padding-bottom: 72px;
-}
-body.site ::selection { background: var(--spot); color: var(--spot-ink); }
-body.site a { color: inherit; }
-body.site .ram {
- background: currentColor; display: block;
- -webkit-mask: url("/assets/ram.svg") center/contain no-repeat;
- mask: url("/assets/ram.svg") center/contain no-repeat;
-}
-body.site .hd-frame {
- max-width: 1440px; margin: 0 auto; background: var(--bg); position: relative;
- border-left: 1px solid var(--line2); border-right: 1px solid var(--line2);
- border-bottom: 1px solid var(--line2);
-}
-
-/* ── nav ── */
-body.site .hd-nav {
- display: flex; align-items: center; gap: 24px;
- height: 60px; padding: 0 var(--gut); border-bottom: 1px solid var(--line2);
-}
-body.site .lock { display: flex; align-items: center; gap: 10px; text-decoration: none; }
-body.site .lock .ram { width: 25px; height: 25px; color: var(--ink); }
-body.site .lock b { font-family: var(--disp); font-weight: 900; font-size: 20px; letter-spacing: -.045em; color: var(--ink); }
-body.site .hd-nav .sp { flex: 1; }
-body.site .hd-nav a.lnk { color: var(--dim); text-decoration: none; font-size: 11.5px; letter-spacing: .07em; text-transform: uppercase; }
-body.site .hd-nav a.lnk:hover { color: var(--ink); }
-body.site .hd-nav .btn { border: 1px solid var(--line2); padding: 7px 15px; color: var(--ink); text-decoration: none; font-size: 11.5px; letter-spacing: .07em; text-transform: uppercase; }
-body.site .hd-nav .btn:hover { background: var(--spot); color: var(--spot-ink); border-color: var(--spot); }
-body.site .hd-nav .ico {
- display: inline-flex; align-items: center; justify-content: center;
- width: 30px; height: 30px; flex: 0 0 auto;
- border: 1px solid var(--line2); color: var(--dim); text-decoration: none;
-}
-body.site .hd-nav .ico.wide { width: auto; gap: 8px; padding: 0 10px; }
-body.site .hd-nav .ico svg { width: 14px; height: 14px; fill: currentColor; }
-body.site .hd-nav .ico b {
- font-family: var(--mono); font-weight: 400; font-size: 11.5px;
- letter-spacing: .04em; font-variant-numeric: tabular-nums;
-}
-body.site .hd-nav .ico.wide:has(b:empty) { width: 30px; gap: 0; padding: 0; }
-body.site .hd-nav .ico:hover { color: var(--spot); border-color: var(--spot); }
-
-body.site .hd-nav .menu {
- display: none; align-items: center; justify-content: center; gap: 4px;
- flex-direction: column; width: 30px; height: 30px; flex: 0 0 auto; padding: 0;
- border: 1px solid var(--line2); background: none; color: var(--dim); cursor: pointer;
-}
-body.site .hd-nav .menu span { display: block; width: 13px; height: 1px; background: currentColor; }
-body.site .hd-nav .menu[aria-expanded="true"] { color: var(--spot); border-color: var(--spot); }
-
-body.site .sheet { display: none; border-bottom: 1px solid var(--line2); }
-body.site .sheet a {
- display: block; padding: 15px var(--gut); text-decoration: none; color: var(--ink);
- font-size: 12px; letter-spacing: .07em; text-transform: uppercase;
- border-bottom: 1px solid var(--line);
-}
-body.site .sheet a:last-of-type { color: var(--dim); }
-body.site .sheet a:active { background: color-mix(in srgb, var(--spot) 8%, transparent); }
-body.site .sheet-ground {
- display: flex; align-items: center; justify-content: space-between; gap: 16px;
- padding: 13px var(--gut);
-}
-body.site .sheet-ground > span {
- color: var(--faint); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
-}
-
-body.site .mode { display: flex; border: 1px solid var(--line2); }
-body.site .mode button {
- background: none; border: 0; color: var(--faint); cursor: pointer;
- font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
- text-transform: uppercase; padding: 7px 10px;
-}
-body.site .mode button:hover { color: var(--ink); }
-body.site .mode button[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
-
-/* ── hero ── */
-body.site .hd-hero { position: relative; overflow: hidden; padding: 68px var(--gut) 56px; }
-body.site .ghost {
- position: absolute; right: -14%; top: 50%; transform: translateY(-50%);
- width: min(880px, 62vw); height: min(880px, 62vw);
- color: var(--mass); z-index: 0; pointer-events: none;
-}
-body.site .hd-hero .in { position: relative; z-index: 1; }
-body.site .hd-eyebrow { display: flex; align-items: center; gap: 14px; color: var(--spot); font-size: 11px; letter-spacing: .3em; text-transform: uppercase; }
-body.site .hd-eyebrow s { width: 42px; height: 1px; background: var(--spot); text-decoration: none; }
-body.site h1 {
- font-family: var(--disp); font-weight: 900; letter-spacing: -.055em; line-height: .88;
- font-size: clamp(38px, 6.6vw, 132px); margin: 24px 0 0; max-width: 20ch; color: var(--ink);
-}
-body.site h1 em { font-style: normal; color: var(--spot); }
-body.site .lede { color: var(--dim); font-size: 15px; line-height: 1.75; max-width: 50ch; margin: 32px 0 0; }
-body.site .lede b { color: var(--ink); font-weight: 400; }
-
-body.site .go { display: flex; align-items: center; gap: 22px; margin-top: 38px; flex-wrap: wrap; }
-body.site .hd-cmd {
- display: inline-flex; align-items: center; border: 1px solid var(--line2);
- background: color-mix(in srgb, var(--bg) 80%, transparent); backdrop-filter: blur(6px);
-}
-body.site .hd-cmd code { padding: 14px 19px; font-size: 13.5px; font-family: var(--mono); }
-body.site .hd-cmd code b { color: var(--spot); font-weight: 400; margin-right: 11px; }
-body.site .hd-cmd button {
- padding: 14px 16px; border: 0; border-left: 1px solid var(--line2); background: none; cursor: pointer;
- color: var(--faint); font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
-}
-body.site .hd-cmd button:hover { color: var(--ink); }
-body.site .meta { margin-top: 20px; color: var(--faint); font-size: 11.5px; letter-spacing: .04em; }
-body.site .meta a { color: var(--spot); text-decoration: none; }
-body.site .meta a:hover { text-decoration: underline; }
-
-/* ── numbers ── */
-body.site .strip { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--line2); border-bottom: 1px solid var(--line2); }
-body.site .stat {
- position: relative; display: block; overflow: hidden; text-decoration: none;
- padding: 24px var(--gut) 26px; border-right: 1px solid var(--line);
-}
-body.site .stat:last-child { border-right: 0; }
-body.site .stat:hover { background: color-mix(in srgb, var(--spot) 5%, transparent); }
-body.site .stat b {
- position: relative; z-index: 1; display: block;
- font-family: var(--disp); font-weight: 900; font-size: clamp(26px, 3vw, 40px);
- letter-spacing: -.045em; line-height: 1; color: var(--ink);
- font-variant-numeric: tabular-nums;
-}
-body.site .stat span {
- position: relative; z-index: 1;
- display: flex; align-items: center; gap: 9px; margin-top: 11px;
- color: var(--faint); font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
-}
-body.site .stat:hover span { color: var(--dim); }
-body.site .stat .ic {
- width: 14px; height: 14px; flex: 0 0 14px;
- fill: currentColor; stroke: currentColor; color: var(--spot); opacity: .85;
-}
-body.site .stat .ic [fill="none"] { fill: none; }
-body.site .stat i.live {
- width: 6px; height: 6px; flex: 0 0 6px; background: var(--run);
- animation: site-pulse 2.2s ease-in-out infinite;
-}
-@keyframes site-pulse { 0%,100% { opacity: .25 } 50% { opacity: 1 } }
-
-
-@media (prefers-reduced-motion: reduce) {
- body.site .stat i.live { animation: none; }
-}
-
-/* ── FIG 1 · the plate ── */
-body.site .fig { padding: 40px var(--gut) 46px; border-bottom: 1px solid var(--line2); }
-body.site .fighd {
- display: flex; align-items: baseline; gap: 16px; padding: 0 0 11px;
- color: var(--faint); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
-}
-body.site .fighd i { font-style: normal; color: var(--spot); letter-spacing: .1em; }
-body.site .fighd .r { margin-left: auto; text-align: right; }
-body.site .figcap {
- margin: 13px 0 0; color: var(--faint); font-size: 11.5px; line-height: 1.7; max-width: 74ch;
-}
-body.site .figcap b { color: var(--dim); font-weight: 400; }
-body.site .plate {
- border: 1px solid var(--line2); overflow: hidden;
- aspect-ratio: 1438 / 620; background: var(--term-bg);
-}
-
-body.site .plate .hero-product-shot { height: 100%; margin: 0; padding: 0; }
-body.site .plate .hero-product-shot figcaption { display: none; }
-body.site .plate .herdr-ui-mock {
- max-width: none; width: 100%; height: 100%; aspect-ratio: auto;
- border: 0; border-radius: 0; box-shadow: none;
- font-size: clamp(.6rem, .92cqw, .95rem);
-}
-/* .mock-main only sets min-width: 0, so as a grid item it grows to its
- content height and the plate never clamps the pane */
-body.site .plate .mock-main { min-height: 0; }
-body.site .plate .mock-panes { grid-template-rows: minmax(0, 1fr); }
-
-/* ── router rows ── */
-body.site .caps { border-bottom: 1px solid var(--line2); }
-body.site .caps > .cap {
- display: grid; grid-template-columns: 130px minmax(0, 58ch) minmax(0, 1fr);
- gap: 0 40px; align-items: start;
- padding: 26px var(--gut); border-bottom: 1px solid var(--line);
- text-decoration: none; cursor: pointer;
-}
-body.site .caps > .cap:last-child { border-bottom: 0; }
-body.site .caps > .cap:hover { background: color-mix(in srgb, var(--spot) 4%, transparent); }
-body.site .caps > .cap:hover h3 { color: var(--spot); }
-/* plain inline: an atomic inline adds a wrap opportunity before it, and
- transforms don't apply to a non-replaced inline — so the nudge is margin */
-body.site .caps .arw {
- margin-left: 4px; vertical-align: 2px;
- font-family: var(--body); font-weight: 400; font-size: 15px; line-height: 1;
- color: var(--faint); transition: color .12s ease, margin-left .12s ease;
-}
-body.site .caps > .cap:hover .arw { color: var(--spot); margin-left: 8px; }
-body.site .caps .n {
- display: flex; flex-direction: column; gap: 13px; align-items: flex-start;
- align-self: start; line-height: 1;
-}
-body.site .caps .n > span:first-child {
- font-family: var(--disp); font-weight: 900; font-size: 44px;
- letter-spacing: -.05em; color: var(--mass); transition: color .12s ease;
-}
-body.site .caps > .cap:hover .n > span:first-child { color: var(--line2); }
-
-body.site .caps .ev {
- align-self: center; justify-self: end;
- width: 100%; max-width: 520px;
- border: 1px solid var(--line2); background: var(--panel);
- padding: 13px 15px;
- font-family: var(--mono); font-size: 11.5px; color: var(--faint);
-}
-body.site .caps .ev-row { display: flex; align-items: center; gap: 14px; padding: 6px 0; }
-body.site .caps .ev-row > span { color: var(--dim); }
-body.site .caps .ev-row b {
- margin-left: auto; font-weight: 400;
- display: inline-flex; align-items: center; gap: 9px;
-}
-body.site .caps .ev-row i { display: block; width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
-body.site .caps .ev-note { margin-top: 9px; line-height: 1.7; }
-
-/* ── 05 ──
- masks are mono because JetBrains Mono carries U+2580–259F; the display
- face would fall back to whatever the system has */
-body.site .caps .cap-soon .mask { font-family: var(--mono); color: var(--line2); letter-spacing: -.02em; }
-body.site .caps .cap-soon .soon-tag {
- font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
- text-transform: uppercase; color: var(--faint);
- border: 1px solid var(--line2); padding: 4px 8px;
-}
-body.site .caps .cap-soon .tape > span { border-right: 0; animation: none; }
-/* available to a screen reader, never on screen */
-body.site .sr {
- position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
- overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
-}
-
-body.site .caps .beat {
- display: block; width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
- background: var(--run); animation: site-pulse 2.2s ease-in-out infinite;
-}
-body.site .caps .ev-row .b { background: var(--st-blocked); }
-body.site .caps .ev-row .w { background: var(--st-working); }
-/* hollow: state_dot() draws idle as ○ */
-body.site .caps .ev-row .i { background: none; box-shadow: inset 0 0 0 2px var(--st-idle); }
-
-body.site .caps .tape {
- display: flex; align-items: baseline; gap: 9px; margin: 0;
- color: var(--dim); min-height: 19px; overflow: hidden; white-space: nowrap;
-}
-body.site .caps .tape b { color: var(--spot); font-weight: 400; }
-/* the caret is the span's own right border so it rides the line box; direct
- child only — row 05 nests a mask span */
-body.site .caps .tape > span {
- flex: 0 1 auto; min-width: 0;
- border-right: 7px solid var(--dim);
- animation: site-caret 1.05s steps(1) infinite;
-}
-@keyframes site-caret { 0%, 49% { border-color: var(--dim) } 50%, 100% { border-color: transparent } }
-
-body.site .caps .herd {
- display: grid; grid-template-columns: 1fr 1fr; gap: 11px 24px; margin: 0;
-}
-body.site .caps .herd span { display: flex; align-items: center; gap: 11px; color: var(--dim); }
-body.site .caps .herd i {
- width: 15px; height: 15px; flex: 0 0 auto; background: var(--faint);
- -webkit-mask: var(--m) center/contain no-repeat;
- mask: var(--m) center/contain no-repeat;
-}
-body.site .caps > .cap:hover .herd i { background: var(--dim); }
-
-@media (prefers-reduced-motion: reduce) {
- body.site .caps .beat,
- body.site .caps .tape > span { animation: none; }
-}
-body.site .caps h3 { margin: 0; font-family: var(--disp); font-weight: 800; letter-spacing: -.03em; font-size: 21px; color: var(--ink); }
-body.site .caps p { margin: 9px 0 0; color: var(--dim); font-size: 13px; line-height: 1.7; max-width: 62ch; }
-body.site .caps h3 { transition: color .12s ease; }
-
-/* ── page head: shared by blog and any other framed page ── */
-body.site .ph { padding: 68px var(--gut) 44px; border-bottom: 1px solid var(--line2); }
-body.site .ph-split {
- display: grid; grid-template-columns: minmax(0, 1fr) auto;
- gap: 60px; align-items: end;
-}
-body.site .ph-side { text-align: right; }
-body.site .ph-side b {
- display: block; font-family: var(--disp); font-weight: 900;
- font-size: clamp(40px, 4.6vw, 68px); letter-spacing: -.05em; line-height: 1; color: var(--ink);
-}
-body.site .ph-side span {
- display: block; margin-top: 10px;
- color: var(--faint); font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
-}
-body.site .ph-side a { display: inline-block; margin-top: 18px; color: var(--spot); text-decoration: none; font-size: 12px; }
-body.site .ph-side a:hover { text-decoration: underline; }
-body.site .ph h1 {
- font-family: var(--disp); font-weight: 900; letter-spacing: -.05em; line-height: .92;
- font-size: clamp(34px, 5vw, 72px); margin: 22px 0 0; max-width: 18ch; color: var(--ink);
-}
-body.site .ph p { margin: 22px 0 0; color: var(--dim); font-size: 14.5px; line-height: 1.75; max-width: 56ch; }
-
-body.site .ph code {
- color: var(--ink); background: var(--panel);
- border: 1px solid var(--line2); padding: 1px 6px; font-size: 12px;
- white-space: nowrap;
-}
-body.site .ph-actions { display: flex; gap: 12px; margin-top: 30px; flex-wrap: wrap; }
-body.site .btn-solid, body.site .btn-ghost {
- text-decoration: none; padding: 12px 18px; font-size: 11.5px;
- letter-spacing: .07em; text-transform: uppercase; border: 1px solid var(--line2);
-}
-body.site .btn-solid { background: var(--spot); border-color: var(--spot); color: var(--spot-ink); }
-body.site .btn-ghost { color: var(--ink); }
-body.site .btn-ghost:hover { background: var(--spot); border-color: var(--spot); color: var(--spot-ink); }
-
-/* `body.site a { color: inherit }` outranks .button-primary's own color, so
- the site language is restated here for style.css's .button classes */
-body.site .button {
- min-height: 0; padding: 12px 18px; border-radius: 0;
- border: 1px solid var(--line2); font-family: var(--mono); font-weight: 400;
- font-size: 11.5px; letter-spacing: .07em; text-transform: uppercase;
-}
-body.site .button-primary { background: var(--spot); border-color: var(--spot); color: var(--spot-ink); }
-body.site .button-primary:hover { background: var(--ink); border-color: var(--ink); color: var(--bg); }
-body.site .button-secondary { background: none; color: var(--ink); }
-body.site .button-secondary:hover { background: var(--spot); border-color: var(--spot); color: var(--spot-ink); }
-
-/* ── plugins ── */
-body.site .plugins-trust {
- display: block; margin: 20px 0 0;
- color: var(--faint); font-size: 12px; line-height: 1.7; max-width: 78ch;
-}
-body.site .plugins-trust .status-dot {
- display: inline-block; width: 7px; height: 7px; border-radius: 50%;
- margin-right: 9px; vertical-align: 1px; background: var(--idle);
-}
-body.site .plugins-trust a { color: var(--spot); text-decoration: none; }
-body.site .plugins-controls {
- display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
- padding: 20px var(--gut); border-bottom: 1px solid var(--line2);
-}
-body.site .plugins-search-wrap { position: relative; flex: 1; min-width: 240px; }
-body.site .plugins-search-icon {
- position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
- color: var(--spot); font-size: 13px;
-}
-body.site .plugins-search {
- width: 100%; background: var(--panel); border: 1px solid var(--line2); border-radius: 0;
- color: var(--ink); font-family: var(--mono); font-size: 13px; padding: 12px 14px 12px 34px;
-}
-body.site .plugins-search::placeholder { color: var(--faint); }
-body.site .plugins-search:focus { outline: 0; border-color: var(--spot); }
-body.site .plugins-sort-wrap { display: flex; align-items: center; gap: 10px; }
-body.site .plugins-sort-label { color: var(--faint); font-size: 10px; letter-spacing: .2em; text-transform: uppercase; }
-body.site .plugins-sort {
- background: var(--panel); border: 1px solid var(--line2); border-radius: 0;
- color: var(--ink); font-family: var(--mono); font-size: 12.5px;
- padding: 11px 34px 11px 13px; cursor: pointer;
- appearance: none; -webkit-appearance: none;
- background-image: linear-gradient(45deg, transparent 50%, var(--faint) 50%),
- linear-gradient(135deg, var(--faint) 50%, transparent 50%);
- background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
- background-size: 5px 5px, 5px 5px;
- background-repeat: no-repeat;
-}
-body.site .plugins-sort:focus { outline: 0; border-color: var(--spot); }
-body.site .plugins-status { margin-left: auto; padding: 0; white-space: nowrap; }
-body.site .plugins-metabar { border-bottom: 1px solid var(--line); }
-body.site .plugins-meta,
-body.site .plugins-status {
- margin: 0; padding: 13px var(--gut); color: var(--faint); font-size: 11.5px;
- letter-spacing: .04em;
-}
-body.site .plugins-status { border-top: 1px solid var(--line); }
-/* neutralise style.css's .section padding/borders on the ported page */
-body.site .plugins-page .section {
- padding: 0; border-top: 0; max-width: none; margin: 0;
-}
-
-body.site .plugins-grid {
- display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
- gap: 14px; padding: 26px var(--gut) 34px;
-}
-body.site .plugin-card {
- display: flex; flex-direction: column; min-width: 0;
- padding: 20px 22px 22px; text-decoration: none;
- background: var(--panel); border: 1px solid var(--line2); border-radius: 0;
- text-transform: none; letter-spacing: normal;
-}
-body.site .plugin-card:hover {
- background: color-mix(in srgb, var(--spot) 6%, var(--panel)); border-color: var(--spot);
-}
-body.site .plugin-card-head { display: flex; align-items: baseline; gap: 12px; }
-body.site .plugin-title { min-width: 0; font-size: 15px; letter-spacing: -.01em; }
-body.site .plugin-owner { color: var(--faint); }
-body.site .plugin-name { color: var(--ink); font-weight: 500; }
-body.site .plugin-card:hover .plugin-name { color: var(--spot); }
-body.site .plugin-go { margin-left: auto; color: var(--faint2); font-size: 14px; }
-body.site .plugin-card:hover .plugin-go { color: var(--spot); }
-body.site .plugin-desc {
- margin: 11px 0 0; color: var(--dim); font-size: 12.5px; line-height: 1.65;
- text-transform: none; letter-spacing: normal;
- display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
- overflow: hidden; min-height: calc(2 * 1.65em);
-}
-body.site .plugin-meta-row {
- display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
- margin-top: auto; padding-top: 18px;
- color: var(--faint); font-size: 12px; letter-spacing: .02em;
-}
-body.site .plugin-stat { display: flex; align-items: center; gap: 7px; }
-body.site .plugin-star { color: var(--spot); }
-body.site .plugin-lang-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
-body.site .plugin-updated { margin-left: auto; color: var(--faint2); }
-body.site .plugins-more {
- display: block; width: 100%; margin: 0; padding: 22px var(--gut);
- border: 0; border-top: 1px solid var(--line2); background: none;
- color: var(--dim); text-align: center; cursor: pointer;
-}
-body.site .plugins-more:hover {
- background: color-mix(in srgb, var(--spot) 5%, transparent); color: var(--spot);
-}
-/* the rule above outranks the page's own [hidden] guard, so restate it */
-body.site .plugins-more[hidden] { display: none; }
-body.site .plugins-publish { padding: 40px var(--gut) 48px; border-bottom: 1px solid var(--line2); }
-body.site .plugins-publish-card { border: 1px solid var(--line2); padding: 26px 28px; }
-body.site .plugins-publish h2,
-body.site .plugins-publish h3 {
- margin: 0; font-family: var(--disp); font-weight: 900; letter-spacing: -.035em;
- font-size: 26px; color: var(--ink);
-}
-body.site .plugins-publish p { margin: 12px 0 0; color: var(--dim); font-size: 13px; line-height: 1.75; max-width: 70ch; }
-body.site .plugins-publish-actions { display: flex; gap: 12px; margin-top: 22px; flex-wrap: wrap; }
-
-/* ── blog index ── */
-body.site .posts { border-bottom: 1px solid var(--line2); }
-body.site .posts a {
- display: grid; grid-template-columns: 132px minmax(0, 1fr) auto;
- gap: 0 30px; align-items: baseline; text-decoration: none;
- padding: 24px var(--gut); border-bottom: 1px solid var(--line);
-}
-body.site .posts a:last-child { border-bottom: 0; }
-body.site .posts a:hover { background: color-mix(in srgb, var(--spot) 5%, transparent); }
-body.site .posts time { color: var(--faint); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; }
-body.site .posts h2 {
- margin: 0; font-family: var(--disp); font-weight: 800; letter-spacing: -.03em;
- font-size: 21px; color: var(--ink);
-}
-body.site .posts p { margin: 8px 0 0; color: var(--dim); font-size: 12.5px; line-height: 1.7; max-width: 74ch; }
-body.site .posts .go-arrow { color: var(--faint); font-size: 15px; }
-body.site .posts a:hover .go-arrow { color: var(--spot); }
-
-/* ── article ── */
-body.site .article {
- display: grid; grid-template-columns: minmax(0, 76ch) 224px; gap: 60px;
- justify-content: center;
- padding: 54px var(--gut) 76px; border-bottom: 1px solid var(--line2); align-items: start;
-}
-body.site .article-solo { grid-template-columns: minmax(0, 1fr); }
-body.site .article-solo .article-body { margin-inline: auto; }
-body.site .article-body { min-width: 0; max-width: 76ch; }
-body.site .article-meta {
- display: flex; gap: 16px; align-items: baseline;
- color: var(--faint); font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
-}
-body.site .article-meta a { color: var(--spot); text-decoration: none; }
-body.site .article h1 {
- font-family: var(--disp); font-weight: 900; letter-spacing: -.045em; line-height: .95;
- font-size: clamp(30px, 3.6vw, 52px); margin: 18px 0 0; color: var(--ink);
-}
-body.site .article-lede { margin: 20px 0 0; color: var(--dim); font-size: 15px; line-height: 1.75; }
-body.site .article-rule { margin: 34px 0 0; border: 0; border-top: 1px solid var(--line2); }
-
-body.site .prose { margin-top: 34px; color: var(--dim); font-size: 13.5px; line-height: 1.85; }
-body.site .prose > * + * { margin-top: 20px; }
-body.site .prose h2 {
- font-family: var(--disp); font-weight: 800; letter-spacing: -.03em; font-size: 25px;
- color: var(--ink); margin-top: 46px; padding-top: 18px; border-top: 1px solid var(--line);
-}
-body.site .prose h3 { font-family: var(--disp); font-weight: 700; font-size: 18px; color: var(--ink); margin-top: 32px; }
-body.site .prose a { color: var(--spot); text-underline-offset: 3px; }
-body.site .prose strong { color: var(--ink); font-weight: 500; }
-body.site .prose code {
- color: var(--ink); background: var(--panel);
- border: 1px solid var(--line2); padding: 1px 6px; font-size: 12px;
-}
-body.site .prose pre {
- background: var(--panel); border: 1px solid var(--line2);
- padding: 16px 18px; overflow-x: auto; font-size: 12.5px; line-height: 1.7;
-}
-body.site .prose pre code { background: none; border: 0; padding: 0; font-size: inherit; }
-body.site .prose ul, body.site .prose ol { padding-left: 22px; }
-body.site .prose li + li { margin-top: 8px; }
-body.site .prose blockquote {
- border-left: 2px solid var(--spot); padding-left: 18px; margin-left: 0; color: var(--faint);
-}
-body.site .prose img { max-width: 100%; border: 1px solid var(--line2); }
-body.site .prose table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
-body.site .prose th, body.site .prose td { text-align: left; padding: 9px 12px; border: 1px solid var(--line); }
-body.site .prose th { color: var(--ink); font-weight: 500; }
-
-/* ── post figures ── */
-body.site .pf { margin: 34px 0 0; }
-body.site .pf-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
-body.site .pf-panel { border: 1px solid var(--line2); background: var(--panel); min-width: 0; }
-body.site .pf-label {
- display: flex; justify-content: space-between; gap: 10px;
- padding: 8px 12px; border-bottom: 1px solid var(--line2);
- color: var(--faint); font-family: var(--mono); font-size: 10px;
- letter-spacing: .16em; text-transform: uppercase;
-}
-body.site .pf-label b { color: var(--dim); font-weight: 400; }
-body.site .pf-cap { margin: 12px 0 0; color: var(--faint); font-size: 11.5px; line-height: 1.6; }
-
-/* agent rows */
-body.site .pf-row {
- display: grid; grid-template-columns: 14px minmax(0, 1fr); gap: 9px; align-items: baseline;
- padding: 7px 12px; font-family: var(--mono); font-size: 12px;
-}
-body.site .pf-row + .pf-row { border-top: 1px solid var(--line); }
-body.site .pf-row strong { color: var(--ink); font-weight: 400; }
-body.site .pf-row small { display: block; color: var(--faint); font-size: 10.5px; }
-body.site .pf-mark { line-height: 1; }
-body.site .pf-row.working .pf-mark, body.site .pf-row.working small { color: var(--st-working); }
-body.site .pf-row.blocked .pf-mark, body.site .pf-row.blocked small { color: var(--st-blocked); }
-body.site .pf-row.done .pf-mark, body.site .pf-row.done small { color: var(--st-done); }
-body.site .pf-row.idle .pf-mark, body.site .pf-row.idle small { color: var(--st-idle); }
-
-body.site .pf-spin { position: relative; display: inline-block; width: 1ch; }
-body.site .pf-spin i { position: absolute; left: 0; top: 0; font-style: normal; opacity: 0; animation: pf-frame .5s steps(1, end) infinite; }
-body.site .pf-spin i:nth-child(2) { animation-delay: .125s; }
-body.site .pf-spin i:nth-child(3) { animation-delay: .25s; }
-body.site .pf-spin i:nth-child(4) { animation-delay: .375s; }
-@keyframes pf-frame { 0%, 24.9% { opacity: 1; } 25%, 100% { opacity: 0; } }
-@media (prefers-reduced-motion: reduce) {
- body.site .pf-spin i { animation: none; }
- body.site .pf-spin i:first-child { opacity: 1; }
-}
-
-/* flow steps */
-body.site .pf-flow { padding: 14px 12px; font-family: var(--mono); font-size: 11.5px; }
-body.site .pf-step { color: var(--dim); padding: 5px 0; }
-body.site .pf-step b { color: var(--ink); font-weight: 400; }
-body.site .pf-step s { display: block; color: var(--faint); text-decoration: none; font-size: 10.5px; padding-top: 2px; }
-body.site .pf-arrow { color: var(--line2); padding: 1px 0; }
-body.site .pf-fork em { color: var(--faint); font-style: normal; margin-right: 8px; }
-body.site .pf-fork s { padding-left: 34px; }
-body.site .pf-stop { color: var(--st-done); }
-body.site .pf-cost { color: var(--st-blocked); }
-
-/* bars */
-body.site .pf-bars { padding: 16px 14px; font-family: var(--mono); font-size: 11px; }
-body.site .pf-bar-row + .pf-bar-row { margin-top: 16px; }
-body.site .pf-bar-name { color: var(--dim); }
-body.site .pf-bar { display: grid; grid-template-columns: 46px minmax(0, 1fr) 58px; gap: 8px; align-items: center; margin-top: 5px; }
-body.site .pf-bar span:first-child { color: var(--faint); font-size: 10px; }
-body.site .pf-bar i { display: block; height: 9px; min-width: 1px; }
-body.site .pf-bar em { color: var(--faint); font-style: normal; text-align: right; }
-body.site .pf-bar.old i { background: var(--line2); }
-body.site .pf-bar.new i { background: var(--spot); }
-body.site .pf-bar.new em { color: var(--dim); }
-
-@media (max-width: 560px) {
- body.site .pf-2 { grid-template-columns: minmax(0, 1fr); }
- body.site .pf-bar { grid-template-columns: 42px minmax(0, 1fr) 52px; }
-}
-
-/* sticky section index */
-body.site .toc { position: sticky; top: 30px; }
-body.site .toc p { margin: 0 0 12px; color: var(--faint); font-size: 10px; letter-spacing: .2em; text-transform: uppercase; }
-body.site .toc nav { display: flex; flex-direction: column; }
-body.site .toc a {
- color: var(--dim); text-decoration: none; font-size: 12px; line-height: 1.5;
- padding: 7px 0 7px 13px; border-left: 1px solid var(--line2);
-}
-body.site .toc a:hover { color: var(--ink); }
-body.site .toc a[aria-current] { color: var(--spot); border-left-color: var(--spot); }
-
-body.site .cmp { padding: 40px var(--gut) 46px; border-bottom: 1px solid var(--line2); }
-body.site .cmp-scroll { overflow-x: auto; }
-body.site .cmp table {
- width: 100%; min-width: 940px; border-collapse: collapse;
- font-family: var(--mono); font-size: 12.5px; line-height: 1.6;
-}
-body.site .cmp th, body.site .cmp td {
- text-align: left; vertical-align: top; padding: 12px 14px;
- border: 1px solid var(--line); color: var(--dim); font-weight: 400;
- background: none;
-}
-body.site .cmp thead th {
- color: var(--faint); font-size: 10px; letter-spacing: .16em;
- text-transform: uppercase; background: var(--panel); white-space: nowrap;
-}
-body.site .cmp tbody th { color: var(--ink); }
-body.site .cmp .h { color: var(--ink); background: color-mix(in srgb, var(--spot) 6%, transparent); }
-body.site .cmp thead .h { color: var(--spot); }
-body.site .cmp .no { color: var(--faint); }
-
-body.site .caps .cap-flat { cursor: default; }
-body.site .caps .cap-flat:hover { background: none; }
-body.site .caps .cap-flat:hover h3 { color: var(--ink); }
-body.site .caps .cap-flat:hover .n > span:first-child { color: var(--mass); }
-
-body.site .vs { padding: 40px var(--gut) 46px; border-bottom: 1px solid var(--line2); }
-body.site .vs-list { border: 1px solid var(--line2); }
-body.site .vs-list article {
- display: grid; grid-template-columns: minmax(150px, 230px) minmax(0, 1fr);
- gap: 0 30px; padding: 16px 18px; border-bottom: 1px solid var(--line);
-}
-body.site .vs-list article:last-child { border-bottom: 0; }
-body.site .vs-list b {
- font-family: var(--mono); font-weight: 400; font-size: 12px;
- letter-spacing: .04em; color: var(--ink);
-}
-body.site .vs-list p { margin: 0; color: var(--dim); font-size: 14px; line-height: 1.7; max-width: 74ch; }
-@media (max-width: 700px) {
- body.site .vs-list article { grid-template-columns: minmax(0, 1fr); gap: 7px 0; }
-}
-
-/* ── close ── */
-body.site .end { position: relative; overflow: hidden; padding: 96px var(--gut) 104px; border-bottom: 1px solid var(--line2); }
-/* the bleed is a fraction of the mark, not the section — a % would resolve
- against .end's height */
-body.site .end .ram {
- --ram-size: min(560px, 54vw);
- position: absolute; right: -6%; bottom: calc(var(--ram-size) * -0.22);
- width: var(--ram-size); height: var(--ram-size); color: var(--mass); z-index: 0;
-}
-body.site .end .in { position: relative; z-index: 1; }
-body.site .end h2 { font-family: var(--disp); font-weight: 900; letter-spacing: -.05em; font-size: clamp(36px, 5.4vw, 70px); line-height: .93; margin: 0; max-width: 13ch; color: var(--ink); }
-body.site .end p { margin: 20px 0 0; color: var(--dim); font-size: 13.5px; max-width: 52ch; line-height: 1.8; }
-
-/* ── footer ── */
-body.site .foot { padding: 22px var(--gut); border-top: 1px solid var(--line2); display: flex; gap: 22px; align-items: center; flex-wrap: wrap; color: var(--faint); font-size: 11.5px; }
-body.site .foot a { color: var(--dim); text-decoration: none; }
-body.site .foot a:hover { color: var(--ink); }
-body.site .foot .ram { width: 15px; height: 15px; color: var(--faint); }
-body.site .meta.yc-meta { margin-top: 10px; }
-body.site .meta .yc { color: var(--dim); display: inline-flex; align-items: center; gap: 6px; }
-body.site .meta .yc img { display: block; }
-body.site .meta .yc:hover { color: var(--ink); text-decoration: none; }
-body.site .foot .fact { color: var(--faint); font-variant-numeric: tabular-nums; }
-body.site .foot .out { margin-left: auto; display: flex; align-items: center; gap: 16px; }
-body.site .foot .ico { display: inline-flex; color: var(--faint); }
-body.site .foot .ico svg { width: 14px; height: 14px; fill: currentColor; }
-body.site .foot .ico:hover { color: var(--ink); }
-
-@media (max-width: 900px) {
- :root { --gut: 20px; }
- body.site { background-size: 40px 40px; padding-bottom: 40px; }
- body.site .hd-nav a.lnk { display: none; }
- body.site .hd-nav .mode { display: none; }
- body.site .hd-nav .menu { display: inline-flex; }
- body.site .sheet.open { display: block; }
- body.site .strip { grid-template-columns: 1fr 1fr; }
- body.site .strip .stat { border-bottom: 1px solid var(--line); }
- body.site .strip .stat:nth-last-child(-n + 2) { border-bottom: 0; }
- body.site .strip .stat:nth-child(2n) { border-right: 0; }
- body.site .caps > .cap { grid-template-columns: 54px minmax(0, 1fr); gap: 0 18px; }
- body.site .caps .n > span:first-child { font-size: 30px; }
- body.site .caps .ev { grid-column: 2; margin-top: 20px; }
- body.site .fig { padding: 26px var(--gut) 30px; }
- body.site .plate { aspect-ratio: auto; }
- body.site .hd-hero { padding: 60px var(--gut) 52px; }
- body.site .article { grid-template-columns: minmax(0, 1fr); }
- body.site .article .toc { display: none; }
-}
-
-@media (max-width: 560px) {
- body.site .hd-nav { gap: 14px; }
- body.site .hd-nav .ico[href*="x.com"] { display: none; }
- body.site .fighd { flex-wrap: wrap; gap: 6px 16px; }
- body.site .fighd .r { margin-left: 0; text-align: left; }
- body.site .end { padding: 56px var(--gut) 64px; }
- body.site .foot .out { margin-left: 0; }
- body.site .foot .ram { display: none; }
- body.site .posts a { grid-template-columns: minmax(0, 1fr) auto; gap: 8px 16px; }
- body.site .posts time { grid-column: 1 / -1; }
- body.site .ph-split { grid-template-columns: minmax(0, 1fr); gap: 30px; }
- body.site .ph-side { text-align: left; }
- body.site .ph-side b { font-size: 44px; }
-}
-
-@media (max-width: 430px) {
- body.site .hd-cmd code { padding: 12px 14px; font-size: 12px; }
- body.site .hd-cmd button { padding: 12px 13px; }
-}
-
-@media (max-width: 380px) {
- :root { --gut: 16px; }
- body.site .hd-nav { gap: 10px; }
- body.site .hd-nav .ico.wide { width: 30px; gap: 0; padding: 0; }
- body.site .hd-nav .ico.wide b { display: none; }
- body.site .hd-cmd { flex-wrap: wrap; }
- body.site .hd-cmd code { flex: 1 1 100%; }
- body.site .hd-cmd button {
- flex: 1 1 100%; text-align: left; padding: 11px 14px;
- border-left: 0; border-top: 1px solid var(--line2);
- }
-}
-
-/* the mock scales on its own width — .hero-product-shot is the container */
-@container (max-width: 900px) {
- body.site .herdr-ui-mock {
- aspect-ratio: auto; height: 74vh; min-height: 460px;
- grid-template-columns: minmax(84px, 27%) minmax(0, 1fr);
- }
- body.site .mock-space, body.site .mock-agent { padding: 6px 8px; }
- body.site .mock-agent-title span:last-child { display: none; }
- body.site .mock-main { min-height: 0; min-width: 0; }
- body.site .mock-view, body.site .mock-pane { min-width: 0; }
- body.site .mock-panes { grid-template-columns: minmax(0, 1fr) !important; min-width: 0; }
- body.site .mock-panes .mock-pane:not(.focused) { display: none; }
-}
-
-@media (prefers-reduced-motion: reduce) {
- body.site .strip i.live { animation: none; }
-}
-
-/* ── typography: mono where it carries identifiers, commands, labels,
- figures; prose stays --body ── */
-body.site .hd-nav a.lnk,
-body.site .hd-nav .btn,
-body.site .hd-eyebrow,
-body.site .meta,
-body.site .stat span,
-body.site .fighd,
-body.site .caps .n,
-body.site .foot,
-body.site .ph-side span,
-body.site .posts time,
-body.site .article-meta,
-body.site .toc p,
-body.site .plugins-search,
-body.site .plugins-sort,
-body.site .plugins-sort-label,
-body.site .plugins-meta,
-body.site .plugins-status,
-body.site .plugin-title,
-body.site .plugin-meta-row,
-body.site .btn-solid,
-body.site .btn-ghost,
-body.site code,
-body.site pre {
- font-family: var(--mono);
-}
-
-body.site .lede { font-size: 16px; line-height: 1.7; max-width: 56ch; }
-body.site .ph p { font-size: 15.5px; line-height: 1.7; max-width: 62ch; }
-body.site .caps p { font-size: 14.5px; line-height: 1.7; color: var(--dim); }
-body.site .end p { font-size: 15px; line-height: 1.75; }
-body.site .figcap { font-size: 13.5px; line-height: 1.7; }
-body.site .posts p { font-size: 14px; line-height: 1.65; }
-body.site .article-lede { font-size: 16.5px; line-height: 1.7; }
-body.site .prose { font-size: 16px; line-height: 1.75; }
-body.site .prose code, body.site .prose pre { font-size: 13.5px; }
-body.site .toc a { font-family: var(--body); font-size: 13px; line-height: 1.5; }
-body.site .plugins-trust { font-size: 13.5px; line-height: 1.7; }
-body.site .plugin-desc { font-size: 14.5px; line-height: 1.6; min-height: calc(2 * 1.6em); }
-body.site .plugin-title { font-size: 15px; }
diff --git a/website/css/style.css b/website/css/style.css
deleted file mode 100644
index d1751e34..00000000
--- a/website/css/style.css
+++ /dev/null
@@ -1,3655 +0,0 @@
-@font-face {
- font-family: "JetBrains Mono";
- font-style: normal;
- font-weight: 400 700;
- font-display: swap;
- src: url("/assets/jbm.woff2?v=2") format("woff2");
- unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC,
- U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
- U+20AC, U+2122, U+2190-2193, U+2212, U+2215, U+2500-2503,
- U+2514, U+2580-259F, U+25C9, U+25CF, U+2713, U+276F,
- U+FEFF, U+FFFD;
-}
-
-:root {
- --bg: #f0eee9;
- --bg-elevated: #f5f3ee;
- --ink: #1a1a18;
- --ink-soft: #3a3a36;
- --muted: #6b6b66;
- --muted-2: #8a8a84;
- --line: #d8d6d0;
- --line-strong: #c4c2bb;
- --terminal: #0c0c0b;
- --terminal-2: #131312;
- --accent: #4a9eff;
- --accent-soft: color-mix(in srgb, var(--accent) 10%, transparent);
- --green: #2d9f52;
- --yellow: #b8860b;
- --red: #c73e3e;
- --radius-lg: 6px;
- --radius-md: 4px;
- --radius-sm: 2px;
- --max: 1160px;
- --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
- --body: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
- --term-bg: #1a1d22;
- --term-sidebar-bg: #15181d;
- --term-active-bg: #20242c;
- --term-tab-bg: #20242c;
- --term-tab-active-bg: #4a9eff;
- --term-tab-active-text: #0c0c0b;
- --term-border: #2b3038;
- --term-text: #c8cdd4;
- --term-muted: #5a6068;
- --term-prompt: #4a9eff;
- --term-cmd: #8ecf7a;
- --term-str: #e6c060;
- --term-dim: #6a7078;
- --term-blue: #4a9eff;
- --term-green-bright: #7ecf8a;
- --logo-filter: none;
- --logo-opacity: 0.72;
-}
-
-[data-palette="herdr"] {
- --bg: #0c0c0b; --bg-elevated: #131312; --ink: #f0ece0; --ink-soft: #dedad0;
- --muted: #8a8a80; --muted-2: #5c5c55; --line: #252522; --line-strong: #2e2e2b;
- --terminal: #0c0c0b; --terminal-2: #131312; --accent: #4a9eff;
- --green: #52c97a; --yellow: #e6b84a; --red: #e05a5a;
- --term-bg: #0c0c0b; --term-sidebar-bg: #131312; --term-active-bg: #191918;
- --term-tab-bg: #191918; --term-tab-active-bg: #4a9eff; --term-tab-active-text: #0c0c0b;
- --term-border: #252522; --term-text: #dedad0; --term-muted: #5c5c55;
- --term-prompt: #4a9eff; --term-cmd: #52c97a; --term-str: #e6b84a;
- --term-dim: #8a8a80; --term-blue: #4a9eff; --term-green-bright: #52c97a;
-}
-[data-palette="taat"] {
- --bg: #0c0c0b; --bg-elevated: #111110; --ink: #f0ece0; --ink-soft: #e2ddd0;
- --muted: #6a6a62; --muted-2: #4a4a44; --line: #252522; --line-strong: #2a2a26;
- --terminal: #0c0c0b; --terminal-2: #111110; --accent: #4a9eff;
- --green: #4a9e6a; --yellow: #c4a84a; --red: #c46a6a;
- --term-bg: #0c0c0b; --term-sidebar-bg: #111110; --term-active-bg: #161614;
- --term-tab-bg: #161614; --term-tab-active-bg: #4a9eff; --term-tab-active-text: #0c0c0b;
- --term-border: #252522; --term-text: #e2ddd0; --term-muted: #4a4a44;
- --term-prompt: #4a9eff; --term-cmd: #4a9e6a; --term-str: #c4a84a;
- --term-dim: #6a6a62; --term-blue: #4a9eff; --term-green-bright: #4a9e6a;
-}
-[data-palette="catppuccin"] {
- --bg: #11111b; --bg-elevated: #181825; --ink: #f5e0dc; --ink-soft: #cdd6f4;
- --muted: #9399b2; --muted-2: #6c7086; --line: #313244; --line-strong: #45475a;
- --terminal: #11111b; --terminal-2: #181825; --accent: #89b4fa;
- --green: #a6e3a1; --yellow: #f9e2af; --red: #f38ba8;
- --term-bg: #11111b; --term-sidebar-bg: #181825; --term-active-bg: #1e1e2e;
- --term-tab-bg: #1e1e2e; --term-tab-active-bg: #89b4fa; --term-tab-active-text: #11111b;
- --term-border: #313244; --term-text: #cdd6f4; --term-muted: #6c7086;
- --term-prompt: #89b4fa; --term-cmd: #a6e3a1; --term-str: #f9e2af;
- --term-dim: #9399b2; --term-blue: #89b4fa; --term-green-bright: #a6e3a1;
-}
-[data-palette="catppuccin-latte"] {
- --bg: #eff1f5; --bg-elevated: #e6e9ef; --ink: #1e1e2e; --ink-soft: #4c4f69;
- --muted: #6c6f85; --muted-2: #9ca0b0; --line: #ccd0da; --line-strong: #bcc0cc;
- --terminal: #eff1f5; --terminal-2: #e6e9ef; --accent: #1e66f5;
- --green: #40a02b; --yellow: #df8e1d; --red: #d20f39;
- --term-bg: #eff1f5; --term-sidebar-bg: #e6e9ef; --term-active-bg: #dce0e8;
- --term-tab-bg: #dce0e8; --term-tab-active-bg: #1e66f5; --term-tab-active-text: #eff1f5;
- --term-border: #ccd0da; --term-text: #4c4f69; --term-muted: #9ca0b0;
- --term-prompt: #1e66f5; --term-cmd: #40a02b; --term-str: #df8e1d;
- --term-dim: #6c6f85; --term-blue: #1e66f5; --term-green-bright: #40a02b;
-}
-[data-palette="terminal"] {
- --bg: #000000; --bg-elevated: #080808; --ink: #ffffff; --ink-soft: #d8d8d8;
- --muted: #888888; --muted-2: #555555; --line: #1a1a1a; --line-strong: #2a2a2a;
- --terminal: #000000; --terminal-2: #080808; --accent: #4a9eff;
- --green: #55d66b; --yellow: #e6d55a; --red: #ff6b6b;
- --term-bg: #000000; --term-sidebar-bg: #080808; --term-active-bg: #101010;
- --term-tab-bg: #101010; --term-tab-active-bg: #4a9eff; --term-tab-active-text: #000000;
- --term-border: #1a1a1a; --term-text: #d8d8d8; --term-muted: #555555;
- --term-prompt: #4a9eff; --term-cmd: #55d66b; --term-str: #e6d55a;
- --term-dim: #888888; --term-blue: #4a9eff; --term-green-bright: #55d66b;
-}
-[data-palette="tokyo-night"] {
- --bg: #1a1b26; --bg-elevated: #202331; --ink: #d5dcff; --ink-soft: #c0caf5;
- --muted: #737aa2; --muted-2: #565f89; --line: #2f3549; --line-strong: #414868;
- --terminal: #1a1b26; --terminal-2: #202331; --accent: #7aa2f7;
- --green: #9ece6a; --yellow: #e0af68; --red: #f7768e;
- --term-bg: #1a1b26; --term-sidebar-bg: #202331; --term-active-bg: #24283b;
- --term-tab-bg: #24283b; --term-tab-active-bg: #7aa2f7; --term-tab-active-text: #1a1b26;
- --term-border: #2f3549; --term-text: #c0caf5; --term-muted: #565f89;
- --term-prompt: #7aa2f7; --term-cmd: #9ece6a; --term-str: #e0af68;
- --term-dim: #737aa2; --term-blue: #7aa2f7; --term-green-bright: #9ece6a;
-}
-[data-palette="tokyo-night-day"] {
- --bg: #e1e2e7; --bg-elevated: #d8d9e0; --ink: #1f2f66; --ink-soft: #3760bf;
- --muted: #68709a; --muted-2: #8990b3; --line: #b6bbd1; --line-strong: #a8aecb;
- --terminal: #e1e2e7; --terminal-2: #d8d9e0; --accent: #2e7de9;
- --green: #587539; --yellow: #8c6c3e; --red: #f52a65;
- --term-bg: #e1e2e7; --term-sidebar-bg: #d8d9e0; --term-active-bg: #c4c8da;
- --term-tab-bg: #c4c8da; --term-tab-active-bg: #2e7de9; --term-tab-active-text: #e1e2e7;
- --term-border: #b6bbd1; --term-text: #3760bf; --term-muted: #8990b3;
- --term-prompt: #2e7de9; --term-cmd: #587539; --term-str: #8c6c3e;
- --term-dim: #68709a; --term-blue: #2e7de9; --term-green-bright: #587539;
-}
-[data-palette="dracula"] {
- --bg: #282a36; --bg-elevated: #303241; --ink: #ffffff; --ink-soft: #f8f8f2;
- --muted: #8a91b4; --muted-2: #6272a4; --line: #44475a; --line-strong: #6272a4;
- --terminal: #282a36; --terminal-2: #303241; --accent: #bd93f9;
- --green: #50fa7b; --yellow: #f1fa8c; --red: #ff5555;
- --term-bg: #282a36; --term-sidebar-bg: #303241; --term-active-bg: #383a4a;
- --term-tab-bg: #383a4a; --term-tab-active-bg: #bd93f9; --term-tab-active-text: #282a36;
- --term-border: #44475a; --term-text: #f8f8f2; --term-muted: #6272a4;
- --term-prompt: #bd93f9; --term-cmd: #50fa7b; --term-str: #f1fa8c;
- --term-dim: #8a91b4; --term-blue: #bd93f9; --term-green-bright: #50fa7b;
-}
-[data-palette="nord"] {
- --bg: #2e3440; --bg-elevated: #343b49; --ink: #ffffff; --ink-soft: #eceff4;
- --muted: #8792a8; --muted-2: #5f6a80; --line: #434c5e; --line-strong: #4c566a;
- --terminal: #2e3440; --terminal-2: #343b49; --accent: #88c0d0;
- --green: #a3be8c; --yellow: #ebcb8b; --red: #bf616a;
- --term-bg: #2e3440; --term-sidebar-bg: #343b49; --term-active-bg: #3b4252;
- --term-tab-bg: #3b4252; --term-tab-active-bg: #88c0d0; --term-tab-active-text: #2e3440;
- --term-border: #434c5e; --term-text: #eceff4; --term-muted: #5f6a80;
- --term-prompt: #88c0d0; --term-cmd: #a3be8c; --term-str: #ebcb8b;
- --term-dim: #8792a8; --term-blue: #88c0d0; --term-green-bright: #a3be8c;
-}
-[data-palette="gruvbox"] {
- --bg: #282828; --bg-elevated: #32302f; --ink: #fbf1c7; --ink-soft: #ebdbb2;
- --muted: #a89984; --muted-2: #928374; --line: #504945; --line-strong: #665c54;
- --terminal: #282828; --terminal-2: #32302f; --accent: #d79921;
- --green: #b8bb26; --yellow: #fabd2f; --red: #fb4934;
- --term-bg: #282828; --term-sidebar-bg: #32302f; --term-active-bg: #3c3836;
- --term-tab-bg: #3c3836; --term-tab-active-bg: #d79921; --term-tab-active-text: #282828;
- --term-border: #504945; --term-text: #ebdbb2; --term-muted: #928374;
- --term-prompt: #d79921; --term-cmd: #b8bb26; --term-str: #fabd2f;
- --term-dim: #a89984; --term-blue: #d79921; --term-green-bright: #b8bb26;
-}
-[data-palette="gruvbox-light"] {
- --bg: #fbf1c7; --bg-elevated: #f2e5bc; --ink: #282828; --ink-soft: #3c3836;
- --muted: #665c54; --muted-2: #928374; --line: #d5c4a1; --line-strong: #bdae93;
- --terminal: #fbf1c7; --terminal-2: #f2e5bc; --accent: #076678;
- --green: #79740e; --yellow: #b57614; --red: #9d0006;
- --term-bg: #fbf1c7; --term-sidebar-bg: #f2e5bc; --term-active-bg: #ebdbb2;
- --term-tab-bg: #ebdbb2; --term-tab-active-bg: #076678; --term-tab-active-text: #fbf1c7;
- --term-border: #d5c4a1; --term-text: #3c3836; --term-muted: #928374;
- --term-prompt: #076678; --term-cmd: #79740e; --term-str: #b57614;
- --term-dim: #665c54; --term-blue: #076678; --term-green-bright: #79740e;
-}
-[data-palette="one-dark"] {
- --bg: #282c34; --bg-elevated: #2c313a; --ink: #d7dae0; --ink-soft: #abb2bf;
- --muted: #7f848e; --muted-2: #5c6370; --line: #3e4451; --line-strong: #4b5263;
- --terminal: #282c34; --terminal-2: #2c313a; --accent: #61afef;
- --green: #98c379; --yellow: #e5c07b; --red: #e06c75;
- --term-bg: #282c34; --term-sidebar-bg: #2c313a; --term-active-bg: #323842;
- --term-tab-bg: #323842; --term-tab-active-bg: #61afef; --term-tab-active-text: #282c34;
- --term-border: #3e4451; --term-text: #abb2bf; --term-muted: #5c6370;
- --term-prompt: #61afef; --term-cmd: #98c379; --term-str: #e5c07b;
- --term-dim: #7f848e; --term-blue: #61afef; --term-green-bright: #98c379;
-}
-[data-palette="one-light"] {
- --bg: #fafafa; --bg-elevated: #f5f5f6; --ink: #202228; --ink-soft: #383a42;
- --muted: #686b77; --muted-2: #a0a1a7; --line: #e5e5e6; --line-strong: #d5d7de;
- --terminal: #fafafa; --terminal-2: #f5f5f6; --accent: #4078f2;
- --green: #50a14f; --yellow: #c18401; --red: #e45649;
- --term-bg: #fafafa; --term-sidebar-bg: #f5f5f6; --term-active-bg: #f0f0f1;
- --term-tab-bg: #f0f0f1; --term-tab-active-bg: #4078f2; --term-tab-active-text: #fafafa;
- --term-border: #e5e5e6; --term-text: #383a42; --term-muted: #a0a1a7;
- --term-prompt: #4078f2; --term-cmd: #50a14f; --term-str: #c18401;
- --term-dim: #686b77; --term-blue: #4078f2; --term-green-bright: #50a14f;
-}
-[data-palette="solarized"] {
- --bg: #002b36; --bg-elevated: #073642; --ink: #eee8d5; --ink-soft: #93a1a1;
- --muted: #839496; --muted-2: #586e75; --line: #164a57; --line-strong: #586e75;
- --terminal: #002b36; --terminal-2: #073642; --accent: #268bd2;
- --green: #859900; --yellow: #b58900; --red: #dc322f;
- --term-bg: #002b36; --term-sidebar-bg: #073642; --term-active-bg: #0b3d4a;
- --term-tab-bg: #0b3d4a; --term-tab-active-bg: #268bd2; --term-tab-active-text: #002b36;
- --term-border: #164a57; --term-text: #93a1a1; --term-muted: #586e75;
- --term-prompt: #268bd2; --term-cmd: #859900; --term-str: #b58900;
- --term-dim: #839496; --term-blue: #268bd2; --term-green-bright: #859900;
-}
-[data-palette="solarized-light"] {
- --bg: #fdf6e3; --bg-elevated: #eee8d5; --ink: #073642; --ink-soft: #657b83;
- --muted: #586e75; --muted-2: #93a1a1; --line: #d6ceb8; --line-strong: #93a1a1;
- --terminal: #fdf6e3; --terminal-2: #eee8d5; --accent: #268bd2;
- --green: #859900; --yellow: #b58900; --red: #dc322f;
- --term-bg: #fdf6e3; --term-sidebar-bg: #eee8d5; --term-active-bg: #e6dec8;
- --term-tab-bg: #e6dec8; --term-tab-active-bg: #268bd2; --term-tab-active-text: #fdf6e3;
- --term-border: #d6ceb8; --term-text: #657b83; --term-muted: #93a1a1;
- --term-prompt: #268bd2; --term-cmd: #859900; --term-str: #b58900;
- --term-dim: #586e75; --term-blue: #268bd2; --term-green-bright: #859900;
-}
-[data-palette="kanagawa"] {
- --bg: #1f1f28; --bg-elevated: #252532; --ink: #f3ead3; --ink-soft: #dcd7ba;
- --muted: #8f8d80; --muted-2: #727169; --line: #363646; --line-strong: #54546d;
- --terminal: #1f1f28; --terminal-2: #252532; --accent: #7e9cd8;
- --green: #76946a; --yellow: #c0a36e; --red: #c34043;
- --term-bg: #1f1f28; --term-sidebar-bg: #252532; --term-active-bg: #2a2a37;
- --term-tab-bg: #2a2a37; --term-tab-active-bg: #7e9cd8; --term-tab-active-text: #1f1f28;
- --term-border: #363646; --term-text: #dcd7ba; --term-muted: #727169;
- --term-prompt: #7e9cd8; --term-cmd: #76946a; --term-str: #c0a36e;
- --term-dim: #8f8d80; --term-blue: #7e9cd8; --term-green-bright: #76946a;
-}
-[data-palette="kanagawa-lotus"] {
- --bg: #f2ecbc; --bg-elevated: #e5ddb0; --ink: #2a2a37; --ink-soft: #545464;
- --muted: #77736a; --muted-2: #a09cac; --line: #cbcbd1; --line-strong: #b7b2a0;
- --terminal: #f2ecbc; --terminal-2: #e5ddb0; --accent: #4d699b;
- --green: #6f894e; --yellow: #77713f; --red: #c84053;
- --term-bg: #f2ecbc; --term-sidebar-bg: #e5ddb0; --term-active-bg: #dcd5ac;
- --term-tab-bg: #dcd5ac; --term-tab-active-bg: #4d699b; --term-tab-active-text: #f2ecbc;
- --term-border: #cbcbd1; --term-text: #545464; --term-muted: #a09cac;
- --term-prompt: #4d699b; --term-cmd: #6f894e; --term-str: #77713f;
- --term-dim: #77736a; --term-blue: #4d699b; --term-green-bright: #6f894e;
-}
-[data-palette="rose-pine"] {
- --bg: #191724; --bg-elevated: #1f1d2e; --ink: #f4f0ff; --ink-soft: #e0def4;
- --muted: #908caa; --muted-2: #6e6a86; --line: #312f45; --line-strong: #403d52;
- --terminal: #191724; --terminal-2: #1f1d2e; --accent: #c4a7e7;
- --green: #9ccfd8; --yellow: #f6c177; --red: #eb6f92;
- --term-bg: #191724; --term-sidebar-bg: #1f1d2e; --term-active-bg: #26233a;
- --term-tab-bg: #26233a; --term-tab-active-bg: #c4a7e7; --term-tab-active-text: #191724;
- --term-border: #312f45; --term-text: #e0def4; --term-muted: #6e6a86;
- --term-prompt: #c4a7e7; --term-cmd: #9ccfd8; --term-str: #f6c177;
- --term-dim: #908caa; --term-blue: #c4a7e7; --term-green-bright: #9ccfd8;
-}
-[data-palette="rose-pine-dawn"] {
- --bg: #faf4ed; --bg-elevated: #f2e9e1; --ink: #191724; --ink-soft: #464261;
- --muted: #797593; --muted-2: #9893a5; --line: #e6ded7; --line-strong: #d8d0ca;
- --terminal: #faf4ed; --terminal-2: #f2e9e1; --accent: #907aa9;
- --green: #56949f; --yellow: #ea9d34; --red: #b4637a;
- --term-bg: #faf4ed; --term-sidebar-bg: #f2e9e1; --term-active-bg: #fffaf3;
- --term-tab-bg: #fffaf3; --term-tab-active-bg: #907aa9; --term-tab-active-text: #faf4ed;
- --term-border: #e6ded7; --term-text: #464261; --term-muted: #9893a5;
- --term-prompt: #907aa9; --term-cmd: #56949f; --term-str: #ea9d34;
- --term-dim: #797593; --term-blue: #907aa9; --term-green-bright: #56949f;
-}
-[data-palette="vesper"] {
- --bg: #101010; --bg-elevated: #1a1a1a; --ink: #ffffff; --ink-soft: #ffffff;
- --muted: #7e7e7e; --muted-2: #5c5c5c; --line: #282828; --line-strong: #343434;
- --terminal: #101010; --terminal-2: #1a1a1a; --accent: #ffc799;
- --green: #99ffe4; --yellow: #ffc799; --red: #ff8080;
- --term-bg: #101010; --term-sidebar-bg: #1a1a1a; --term-active-bg: #232323;
- --term-tab-bg: #232323; --term-tab-active-bg: #ffc799; --term-tab-active-text: #101010;
- --term-border: #282828; --term-text: #ffffff; --term-muted: #5c5c5c;
- --term-prompt: #ffc799; --term-cmd: #99ffe4; --term-str: #ffc799;
- --term-dim: #7e7e7e; --term-blue: #ffc799; --term-green-bright: #99ffe4;
-}
-
-[data-palette="herdr"],
-[data-palette="taat"],
-[data-palette="catppuccin"],
-[data-palette="terminal"],
-[data-palette="tokyo-night"],
-[data-palette="dracula"],
-[data-palette="nord"],
-[data-palette="gruvbox"],
-[data-palette="one-dark"],
-[data-palette="solarized"],
-[data-palette="kanagawa"],
-[data-palette="rose-pine"],
-[data-palette="vesper"] {
- --logo-filter: invert(1) hue-rotate(180deg) brightness(1.08) contrast(0.9) saturate(1.05);
- --logo-opacity: 0.72;
-}
-
-*,
-*::before,
-*::after {
- box-sizing: border-box;
-}
-
-html {
- background: var(--bg);
- color: var(--ink);
- font-family: var(--body);
- font-size: 16px;
- line-height: 1.65;
- -webkit-font-smoothing: antialiased;
- scroll-behavior: smooth;
-}
-
-body {
- margin: 0;
- min-width: 320px;
- background: var(--bg);
-}
-
-img,
-video {
- max-width: 100%;
- display: block;
-}
-
-button,
-a {
- font: inherit;
-}
-
-a {
- color: inherit;
- text-decoration: none;
-}
-
-a:hover {
- color: var(--accent);
-}
-
-code,
-pre,
-kbd,
-samp {
- font-family: var(--mono);
-}
-
-::selection {
- background: var(--accent-soft);
-}
-
-.site-header {
- position: sticky;
- top: 0;
- z-index: 20;
- backdrop-filter: blur(12px);
- background: color-mix(in srgb, var(--bg) 92%, transparent);
- border-bottom: 1px solid var(--line);
-}
-
-.nav {
- max-width: var(--max);
- margin: 0 auto;
- padding: 0.85rem 1.25rem;
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1rem;
-}
-
-.brand {
- display: inline-flex;
- align-items: center;
- gap: 0.55rem;
- font-family: var(--mono);
- font-weight: 700;
- letter-spacing: -0.04em;
- color: var(--ink);
-}
-
-.brand-logo {
- position: relative;
- display: inline-block;
- width: 32px;
- height: 32px;
- flex: 0 0 auto;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
- cursor: context-menu;
-}
-
-.brand-logo::before {
- content: "";
- position: absolute;
- inset: 2px;
- background: var(--ink);
- -webkit-mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
- mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
-}
-
-.logo-menu {
- position: fixed;
- z-index: 1000;
- min-width: 170px;
- padding: 0.35rem;
- border: 1px solid var(--line-strong);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
-}
-
-.logo-menu a,
-.logo-menu button {
- display: block;
- width: 100%;
- border: 0;
- border-radius: var(--radius-sm);
- background: transparent;
- color: var(--ink-soft);
- padding: 0.5rem 0.65rem;
- font: inherit;
- font-size: 0.85rem;
- font-weight: 600;
- text-align: left;
- cursor: pointer;
-}
-
-.logo-menu a:hover,
-.logo-menu button:hover {
- background: var(--accent-soft);
- color: var(--accent);
-}
-
-.nav-links {
- display: flex;
- align-items: center;
- gap: 1.25rem;
- color: var(--muted);
- font-size: 0.9rem;
- font-family: var(--mono);
-}
-
-.nav-menu {
- position: relative;
- display: none;
- margin-left: auto;
-}
-
-.nav-menu-button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- flex-direction: column;
- gap: 0.22rem;
- width: 2.1rem;
- height: 2.1rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- color: var(--ink-soft);
- cursor: pointer;
- list-style: none;
- transition:
- color 120ms ease,
- border-color 120ms ease,
- background 120ms ease;
-}
-
-.nav-menu-button::-webkit-details-marker {
- display: none;
-}
-
-.nav-menu-button::marker {
- content: "";
-}
-
-.nav-menu-button span {
- display: block;
- width: 0.92rem;
- height: 1px;
- background: currentColor;
-}
-
-.nav-menu-button:hover,
-.nav-menu[open] .nav-menu-button {
- color: var(--accent);
- border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
- background: var(--accent-soft);
-}
-
-.nav-menu-panel {
- position: absolute;
- top: calc(100% + 0.65rem);
- right: 0;
- z-index: 30;
- display: grid;
- min-width: min(18rem, calc(100vw - 2rem));
- padding: 0.35rem;
- border: 1px solid var(--line-strong);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
- box-shadow: 0 16px 44px rgba(0, 0, 0, 0.16);
-}
-
-.nav-menu-panel a {
- border-radius: var(--radius-sm);
- padding: 0.62rem 0.7rem;
- color: var(--ink-soft);
- font-family: var(--mono);
- font-size: 0.86rem;
- font-weight: 600;
-}
-
-.nav-menu-panel a:hover,
-.nav-menu-panel a[aria-current="page"] {
- background: var(--accent-soft);
- color: var(--accent);
-}
-
-.nav-links a,
-.footer a,
-.inline-links a {
- transition: color 0.15s ease;
-}
-
-.nav-tools {
- display: flex;
- align-items: center;
- gap: 0.45rem;
-}
-
-.nav-icon-link {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 2.1rem;
- height: 2.1rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- color: var(--muted);
- transition:
- color 120ms ease,
- border-color 120ms ease,
- background 120ms ease;
-}
-
-.nav-icon-link:hover {
- color: var(--accent);
- border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
- background: var(--accent-soft);
-}
-
-.nav-icon-link svg {
- width: 1rem;
- height: 1rem;
- fill: currentColor;
-}
-
-.nav-cta {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- height: 2.1rem;
- padding: 0 0.9rem;
- border: 1px solid var(--line-strong);
- border-radius: var(--radius-md);
- background: transparent;
- color: var(--ink-soft);
- font-family: var(--mono);
- font-size: 0.82rem;
- font-weight: 600;
-}
-
-.nav-cta:hover {
- border-color: var(--accent);
- color: var(--accent);
- background: var(--accent-soft);
-}
-
-.theme-hint {
- position: fixed;
- bottom: 1rem;
- left: 1rem;
- z-index: 30;
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.45rem 0.7rem;
- border: 1px solid var(--line-strong);
- border-radius: var(--radius-md);
- background: color-mix(in srgb, var(--bg) 92%, transparent);
- backdrop-filter: blur(8px);
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.72rem;
- font-weight: 600;
- cursor: pointer;
- transition: border-color 0.12s ease, color 0.12s ease;
-}
-
-.theme-hint::after {
- content: "";
- position: absolute;
- inset: -4px;
- border: 1px solid var(--accent);
- border-radius: calc(var(--radius-md) + 4px);
- opacity: 0;
- pointer-events: none;
-}
-
-.theme-hint:not(.is-seen)::after {
- animation: theme-hint-pulse 3.6s ease-in-out infinite;
-}
-
-.theme-hint:not(.is-seen) .theme-hint-dot {
- animation: theme-hint-dot 3.6s ease-in-out infinite;
-}
-
-.theme-hint:hover {
- border-color: var(--accent);
- color: var(--accent);
- background: var(--accent-soft);
-}
-
-.theme-hint-dot {
- display: inline-block;
- width: 0.5rem;
- height: 0.5rem;
- border-radius: 50%;
- background: conic-gradient(var(--accent) 25%, var(--green) 25% 50%, var(--yellow) 50% 75%, var(--red) 75%);
- flex: 0 0 auto;
-}
-
-.theme-hint-key {
- color: var(--muted-2);
- font-size: 0.65rem;
-}
-
-.theme-overlay {
- position: fixed;
- inset: 0;
- z-index: 100;
- display: flex;
- align-items: center;
- justify-content: center;
- background: rgba(0, 0, 0, 0.15);
- backdrop-filter: blur(1px);
-}
-
-.theme-overlay[hidden] {
- display: none;
-}
-
-.theme-overlay-panel {
- width: min(480px, calc(100vw - 2rem));
- max-height: calc(100vh - 4rem);
- display: flex;
- flex-direction: column;
- overflow: hidden;
- border: 2px solid var(--accent);
- border-radius: 2px;
- background: var(--term-bg);
- font-family: var(--mono);
- color: var(--term-text);
- box-shadow: 0 24px 80px rgba(0, 0, 0, 0.4);
-}
-
-.theme-overlay-title {
- padding: 0.7rem 1rem 0.2rem;
- color: var(--term-text);
- font-size: 0.92rem;
- font-weight: 700;
- letter-spacing: 0.02em;
-}
-
-.theme-overlay-tabs {
- display: flex;
- align-items: center;
- gap: 0.15rem;
- padding: 0.2rem 1rem 0.6rem;
- border-bottom: 1px solid var(--term-border);
- color: var(--term-muted);
- font-size: 0.78rem;
- font-weight: 600;
-}
-
-.theme-overlay-tabs span {
- padding: 0.2rem 0.5rem;
- border-radius: 1px;
-}
-
-.theme-overlay-tabs span.active {
- background: var(--accent);
- color: var(--term-tab-active-text);
-}
-
-.theme-overlay-list {
- flex: 1;
- overflow-y: auto;
- padding: 0.8rem 0.6rem;
- scrollbar-width: thin;
- scrollbar-color: var(--term-border) transparent;
-}
-
-.theme-overlay-list::-webkit-scrollbar {
- width: 5px;
-}
-
-.theme-overlay-list::-webkit-scrollbar-thumb {
- background: var(--term-border);
- border-radius: 1px;
-}
-
-.theme-sep {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.3rem 0.8rem;
- margin-top: 0.3rem;
- color: var(--term-muted);
- font-family: inherit;
- font-size: 0.72rem;
- font-weight: 700;
- text-transform: lowercase;
- pointer-events: none;
- user-select: none;
-}
-
-.theme-sep:first-child {
- margin-top: 0;
-}
-
-.theme-sep::after {
- content: "";
- flex: 1;
- height: 1px;
- background: var(--term-border);
- opacity: 0.6;
-}
-
-.theme-overlay-list button {
- display: flex;
- align-items: center;
- width: 100%;
- padding: 0.35rem 0.8rem;
- border: 0;
- border-radius: 1px;
- background: transparent;
- color: var(--term-text);
- font-family: inherit;
- font-size: 0.82rem;
- font-weight: 400;
- text-align: left;
- cursor: pointer;
- white-space: nowrap;
- line-height: 1.5;
-}
-
-.theme-overlay-list button::before {
- content: "";
- display: inline-block;
- width: 0.9rem;
- flex: 0 0 auto;
- text-align: center;
-}
-
-.theme-overlay-list button:hover,
-.theme-overlay-list button:focus-visible {
- outline: none;
- background: var(--term-active-bg);
- color: var(--term-text);
-}
-
-.theme-overlay-list button[aria-selected="true"] {
- background: var(--term-active-bg);
- color: var(--term-text);
- font-weight: 700;
-}
-
-.theme-overlay-list button[aria-selected="true"]::before {
- content: "▸";
- color: var(--term-text);
- font-size: 0.7rem;
-}
-
-.theme-overlay-list button[aria-selected="true"]::after {
- content: "✓";
- margin-left: auto;
- color: var(--term-text);
- font-size: 0.78rem;
- font-weight: 400;
-}
-
-.theme-overlay-footer {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1rem;
- padding: 0.55rem 1rem;
- border-top: 1px solid var(--term-border);
- color: var(--term-muted);
- font-size: 0.72rem;
- font-weight: 400;
-}
-
-.theme-overlay-actions {
- display: inline-flex;
- align-items: center;
- gap: 1rem;
-}
-
-.theme-overlay-footer .key {
- color: var(--term-muted);
- font-weight: 700;
-}
-
-.theme-apply-btn {
- display: inline-block;
- padding: 0.15rem 0.5rem;
- background: var(--accent);
- color: var(--term-tab-active-text);
- font-weight: 700;
- border-radius: 1px;
-}
-
-.theme-close-btn {
- border: 0;
- border-radius: 1px;
- background: var(--term-active-bg);
- color: var(--term-muted);
- padding: 0.15rem 0.5rem;
- font-family: inherit;
- font-size: inherit;
- font-weight: 700;
- cursor: pointer;
-}
-
-.theme-close-btn:hover,
-.theme-close-btn:focus-visible {
- outline: none;
- color: var(--term-text);
- background: var(--term-border);
-}
-
-.section,
-.demo-section,
-.footer,
-.final-cta {
- max-width: var(--max);
- margin: 0 auto;
- padding-inline: 1.25rem;
-}
-
-.hero {
- position: relative;
- display: grid;
- grid-template-columns: 1fr 1fr;
- min-height: calc(100vh - 56px);
- border-bottom: 1px solid var(--line);
-}
-
-.hero-left {
- display: flex;
- flex-direction: column;
- justify-content: center;
- padding: 4rem 3rem 4rem 2.5rem;
- border-right: 1px solid var(--line);
-}
-
-.hero-right {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 3rem 2.5rem;
- background: var(--bg-elevated);
- overflow: hidden;
-}
-
-.hero-right::before {
- content: '';
- position: absolute;
- inset: 0;
- background-image:
- linear-gradient(var(--line) 1px, transparent 1px),
- linear-gradient(90deg, var(--line) 1px, transparent 1px);
- background-size: 32px 32px;
- opacity: 0.4;
- pointer-events: none;
-}
-
-.hero-right::after {
- content: '';
- position: absolute;
- inset: 0;
- background: radial-gradient(ellipse at center, transparent 35%, var(--bg-elevated) 80%);
- pointer-events: none;
-}
-
-.hero-copy,
-.hero-product-shot {
- position: relative;
- z-index: 1;
-}
-
-.eyebrow,
-.section-kicker {
- margin: 0 0 1rem;
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.78rem;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: lowercase;
-}
-
-.hero h1,
-.section h2,
-.final-cta h2 {
- margin: 0;
- color: var(--ink);
- letter-spacing: -0.04em;
- line-height: 1.05;
- font-family: var(--mono);
- font-weight: 400;
-}
-
-.hero h1 {
- max-width: 760px;
- font-size: clamp(2.6rem, 5.5vw, 4.6rem);
- text-wrap: balance;
-}
-
-.hero-lede {
- max-width: 560px;
- margin: 1.25rem 0 0;
- color: var(--ink-soft);
- font-size: clamp(1rem, 1.8vw, 1.2rem);
- line-height: 1.6;
-}
-
-.state {
- font-weight: 600;
- font-family: var(--mono);
-}
-
-.state.blocked {
- color: var(--red);
-}
-
-.state.working {
- color: var(--yellow);
-}
-
-.state.done {
- color: var(--green);
-}
-
-.status-dot {
- display: inline-block;
- width: 0.5rem;
- height: 0.5rem;
- border-radius: 50%;
- flex: 0 0 auto;
-}
-
-.dot-blocked {
- background: var(--red);
-}
-
-.dot-working {
- background: var(--yellow);
-}
-
-.dot-done {
- background: var(--green);
-}
-
-.dot-idle {
- background: var(--muted);
-}
-
-.hero-actions {
- display: flex;
- flex-wrap: wrap;
- gap: 0.6rem;
- margin-top: 1.75rem;
-}
-
-.hero-actions.center {
- justify-content: center;
-}
-
-.button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- min-height: 2.6rem;
- padding: 0.6rem 1.1rem;
- border-radius: var(--radius-md);
- font-family: var(--mono);
- font-weight: 600;
- font-size: 0.9rem;
- border: 1px solid transparent;
- transition: all 0.12s ease;
-}
-
-.button-primary {
- background: var(--ink);
- color: var(--bg);
-}
-
-.button-primary:hover {
- background: var(--accent);
- color: #fff;
-}
-
-.button-secondary {
- background: transparent;
- border-color: var(--line-strong);
- color: var(--ink-soft);
-}
-
-.button-secondary:hover {
- border-color: var(--accent);
- color: var(--accent);
- background: var(--accent-soft);
-}
-
-.install-panel {
- max-width: 520px;
- margin-top: 1.25rem;
-}
-
-.install-methods {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- gap: 0.35rem;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.72rem;
- font-weight: 600;
-}
-
-.install-label {
- width: 100%;
- color: var(--muted);
-}
-
-.install-method {
- border: 1px solid var(--term-border);
- border-radius: var(--radius-sm);
- background: var(--term-bg);
- color: var(--muted);
- cursor: pointer;
- min-height: 2rem;
- padding: 0.4rem 0.7rem;
- font-family: var(--mono);
- font-weight: 600;
-}
-
-.install-method:hover,
-.install-method:focus-visible {
- color: var(--ink);
- outline: none;
-}
-
-.install-method.is-active {
- border-color: var(--accent);
- background: var(--accent-soft);
- color: var(--accent);
-}
-
-.install-card {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr) auto;
- align-items: center;
- gap: 0.6rem;
- margin-top: 0.5rem;
- padding: 0.7rem 0.85rem;
- border-radius: var(--radius-md);
- background: var(--term-bg);
- color: var(--term-text);
- border: 1px solid var(--term-border);
-}
-
-.install-card code {
- min-width: 0;
- overflow-x: auto;
- overflow-y: hidden;
- white-space: nowrap;
- scrollbar-width: none;
- font-size: 0.82rem;
-}
-
-.install-card code.is-compact {
- font-size: clamp(0.65rem, 1.1vw, 0.78rem);
-}
-
-.install-card code::-webkit-scrollbar {
- display: none;
-}
-
-.prompt {
- color: var(--accent);
- font-family: var(--mono);
- font-weight: 700;
-}
-
-.install-card button {
- border: 1px solid var(--term-border);
- border-radius: var(--radius-sm);
- background: var(--term-active-bg);
- color: var(--term-text);
- cursor: pointer;
- padding: 0.3rem 0.65rem;
- font-family: var(--mono);
- font-size: 0.72rem;
- font-weight: 600;
-}
-
-.install-card button:hover {
- background: var(--accent-soft);
- border-color: var(--accent);
- color: var(--accent);
-}
-
-.windows-install {
- margin-top: 0.85rem;
- padding-top: 0.85rem;
- border-top: 1px solid var(--line);
-}
-
-.windows-install-heading {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 0.75rem;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.72rem;
- font-weight: 600;
-}
-
-.windows-install-heading span {
- color: var(--ink-soft);
-}
-
-.windows-install-heading a {
- color: var(--accent);
- text-decoration: none;
-}
-
-.windows-install-heading a:hover {
- text-decoration: underline;
-}
-
-.install-card-secondary {
- margin-top: 0.45rem;
- background: color-mix(in srgb, var(--term-bg) 82%, transparent);
-}
-
-.install-card-secondary .prompt {
- font-size: 0.72rem;
-}
-
-.install-card-secondary code {
- font-size: 0.68rem;
-}
-
-.install-card-secondary button {
- padding: 0.24rem 0.55rem;
- font-size: 0.68rem;
-}
-
-.hero-note {
- margin: 0.75rem 0 0;
- color: var(--muted-2);
- font-size: 0.82rem;
- font-family: var(--mono);
-}
-
-.hero-product-shot {
- margin: 0;
- width: 100%;
- container-type: inline-size;
-}
-
-.hero-product-shell {
- overflow: hidden;
- border-radius: var(--radius-lg);
- background: var(--terminal);
- border: 1px solid var(--line-strong);
-}
-
-.hero-product-shell img {
- width: 100%;
- aspect-ratio: 2560 / 1401;
- object-fit: cover;
-}
-
-.hero-product-shot figcaption {
- margin-top: 0.6rem;
- color: var(--muted);
- font-size: 0.78rem;
- text-align: center;
- font-family: var(--mono);
-}
-
-.herdr-ui-mock {
- display: grid;
- grid-template-columns: minmax(120px, 17%) minmax(0, 1fr);
- overflow: hidden;
- aspect-ratio: 2560 / 1401;
- border-radius: var(--radius-lg);
- background: var(--term-bg);
- color: var(--term-muted);
- font-family: var(--mono);
- font-size: clamp(0.44rem, 0.72vw, 0.64rem);
- font-size: clamp(0.4rem, 1.36cqw, 0.64rem);
- line-height: 1.38;
- user-select: none;
- border: 1px solid var(--term-border);
-}
-
-.mock-sidebar {
- display: flex;
- flex-direction: column;
- min-width: 0;
- border-right: 1px solid var(--term-border);
- background: var(--term-sidebar-bg);
-}
-
-.mock-sidebar-title {
- padding: 0.5rem 0.7rem;
- color: var(--term-muted);
- font-weight: 700;
- font-family: var(--mono);
-}
-
-.mock-space {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: 0.45rem;
- align-items: start;
- padding: 0.55rem 0.7rem;
- color: var(--term-dim);
-}
-
-.mock-space.active {
- background: var(--term-active-bg);
-}
-
-.mock-space strong,
-.mock-agent strong {
- display: block;
- overflow: hidden;
- color: var(--term-text);
- font-weight: 700;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-
-.mock-space small,
-.mock-agent small {
- display: block;
- overflow: hidden;
- margin-top: 0.16rem;
- color: var(--term-muted);
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-
-.mock-space.active small {
- color: var(--accent);
-}
-
-.mock-dot {
- width: 0.38rem;
- height: 0.38rem;
- margin-top: 0.25rem;
- border-radius: 50%;
-}
-
-/* Two equal halves, like the TUI's default sidebar_section_split of 0.5. */
-.mock-sidebar-half {
- flex: 1 1 0;
- min-height: 0;
- overflow: hidden;
-}
-
-.mock-sidebar-agents {
- border-top: 1px solid var(--term-border);
-}
-
-.mock-sidebar-row,
-.mock-agent-title {
- display: flex;
- justify-content: space-between;
- padding: 0.45rem 0.7rem;
- color: var(--term-muted);
- font-weight: 700;
- font-family: var(--mono);
-}
-
-.mock-sidebar-row {
- border-bottom: 1px solid var(--term-border);
-}
-
-.mock-agent-title {
- text-transform: lowercase;
-}
-
-.mock-agent {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: 0.4rem;
- padding: 0.38rem 0.7rem;
-}
-
-.mock-agent.active {
- background: var(--term-active-bg);
-}
-
-.mock-agent > span {
- color: var(--term-green-bright);
- line-height: 1.1;
-}
-
-.mock-agent > div {
- min-width: 0;
-}
-
-.mock-agent.working > span,
-.mock-agent.working small {
- color: var(--term-str);
-}
-
-.mock-agent.blocked > span,
-.mock-agent.blocked small {
- color: var(--red);
-}
-
-.mock-agent.done > span,
-.mock-agent.done small {
- color: var(--accent);
-}
-
-.mock-main {
- display: grid;
- grid-template-rows: auto minmax(0, 1fr);
- min-width: 0;
-}
-
-.mock-tabs {
- display: flex;
- align-items: center;
- height: 1.35rem;
- background: var(--term-tab-bg);
- color: var(--term-muted);
-}
-
-.mock-tabs span {
- min-width: 4.6rem;
- padding: 0.24rem 0.7rem;
- border-right: 1px solid var(--term-border);
-}
-
-.mock-tabs span.active {
- background: var(--term-tab-active-bg);
- color: var(--term-tab-active-text);
- font-weight: 800;
-}
-
-.mock-tabs span:last-child {
- min-width: 2rem;
-}
-
-.mock-panes {
- display: grid;
- grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
- gap: 1ch;
- min-height: 0;
- padding: 0;
-}
-
-.mock-pane {
- position: relative;
- min-width: 0;
- overflow: hidden;
- background: var(--term-bg);
- padding: 1lh 1.4ch;
-}
-
-/* Border line runs through the middle of the edge cell, like a box-drawing glyph. */
-.mock-pane::before {
- content: "";
- position: absolute;
- top: 50%;
- left: 50%;
- translate: -50% -50%;
- width: calc(100% - 1ch);
- height: calc(100% - 1lh);
- border: 1px solid var(--term-border);
- pointer-events: none;
-}
-
-.mock-pane.focused::before {
- border-color: var(--accent);
-}
-
-/* Pane title embedded in the top border, one cell in from the left. */
-.mock-pane[data-title]::after {
- content: attr(data-title);
- position: absolute;
- top: 0.5lh;
- left: 2ch;
- translate: 0 -50%;
- padding: 0 0.6ch;
- background: var(--term-bg);
- color: var(--term-muted);
- line-height: 1.1;
- pointer-events: none;
-}
-
-.mock-pane.focused[data-title]::after {
- color: var(--accent);
- font-weight: 700;
-}
-
-/* Single-pane tabs draw no pane chrome, matching the TUI's multi-pane gate. */
-.mock-panes.single .mock-pane::before,
-.mock-panes.single .mock-pane::after {
- content: none;
-}
-
-.mock-panes.single .mock-pane {
- padding: 0.5lh 1.4ch;
-}
-
-.mock-prompt {
- margin-bottom: 0.25rem;
- color: var(--term-prompt);
- font-size: 1.08em;
- font-weight: 700;
-}
-
-.mock-prompt em {
- color: var(--term-dim);
- font-style: normal;
- font-weight: 500;
-}
-
-.mock-pane b {
- color: var(--accent);
-}
-
-.herdr-ui-mock .cmd {
- color: var(--term-cmd);
-}
-
-.herdr-ui-mock .str {
- color: var(--term-str);
-}
-
-.herdr-ui-mock pre {
- margin: 0.55rem 0 0.75rem;
- color: var(--term-text);
- white-space: pre;
-}
-
-.herdr-ui-mock .dim,
-.herdr-ui-mock .time {
- color: var(--term-dim);
-}
-
-.herdr-ui-mock .blue,
-.herdr-ui-mock .url-line span {
- color: var(--term-blue);
-}
-
-.herdr-ui-mock .green {
- color: var(--term-green-bright);
-}
-
-.herdr-ui-mock .badge {
- display: inline-block;
- padding: 0.1rem 0.45rem;
- background: var(--term-green-bright);
- color: var(--term-bg);
- font-weight: 800;
-}
-
-.cursor {
- display: inline-block;
- width: 0.4rem;
- height: 0.85rem;
- background: var(--term-text);
- vertical-align: -0.14rem;
-}
-
-.demo-section {
- padding-top: 0;
- padding-bottom: 5rem;
-}
-
-.demo-video {
- width: 100%;
- overflow: hidden;
- aspect-ratio: 16 / 9;
- border-radius: var(--radius-lg);
- background: var(--terminal);
- object-fit: cover;
- border: 1px solid var(--line-strong);
-}
-
-.nav-icon-link.has-count {
- width: auto;
- padding-inline: 0.55rem;
- gap: 0.35rem;
-}
-
-.nav-icon-link.has-count:has(.nav-star-count:empty) {
- width: 2.1rem;
- padding-inline: 0;
- gap: 0;
-}
-
-.nav-star-count {
- font-family: var(--mono);
- font-size: 0.78rem;
- line-height: 1;
-}
-
-.hero-note a {
- color: inherit;
- text-decoration: underline;
- text-underline-offset: 2px;
- transition: color 0.12s ease;
-}
-
-.hero-note a:hover {
- color: var(--accent);
-}
-
-.community-section {
- padding-top: 4.25rem;
-}
-
-.section.community-section {
- border-top: none;
-}
-
-.community-video-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.75rem;
-}
-
-.community-video-card {
- display: flex;
- flex-direction: column;
- min-width: 0;
- overflow: hidden;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
- color: var(--ink-soft);
- transition:
- border-color 120ms ease,
- transform 120ms ease,
- background 120ms ease;
-}
-
-.community-video-card:hover {
- transform: translateY(-2px);
- border-color: color-mix(in srgb, var(--accent) 42%, var(--line));
- background: color-mix(in srgb, var(--bg-elevated) 88%, var(--accent-soft));
- color: var(--ink-soft);
-}
-
-.community-video-thumb {
- position: relative;
- display: block;
- overflow: hidden;
- aspect-ratio: 16 / 9;
- background: var(--term-bg);
- border-bottom: 1px solid var(--line);
-}
-
-.community-video-image {
- display: block;
- width: 100%;
- height: 100%;
- background-image: var(--thumbnail);
- background-position: center;
- background-size: cover;
- transition: transform 180ms ease;
-}
-
-.community-video-card:hover .community-video-image {
- transform: scale(1.025);
-}
-
-.play-badge {
- position: absolute;
- right: 0.75rem;
- bottom: 0.75rem;
- display: grid;
- place-items: center;
- width: 2.3rem;
- height: 2.3rem;
- border: 1px solid color-mix(in srgb, #fff 45%, transparent);
- border-radius: 50%;
- background: color-mix(in srgb, var(--term-bg) 78%, transparent);
- backdrop-filter: blur(8px);
-}
-
-.play-badge::before {
- content: "";
- display: block;
- width: 0;
- height: 0;
- margin-left: 0.16rem;
- border-top: 0.42rem solid transparent;
- border-bottom: 0.42rem solid transparent;
- border-left: 0.68rem solid #fff;
-}
-
-.community-video-copy {
- display: flex;
- flex: 1;
- flex-direction: column;
- gap: 0.45rem;
- padding: 1rem;
-}
-
-.community-video-meta {
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.68rem;
- font-weight: 700;
- letter-spacing: 0.08em;
- text-transform: uppercase;
-}
-
-.community-video-title {
- color: var(--ink);
- font-family: var(--mono);
- font-size: 1.05rem;
- font-weight: 400;
- letter-spacing: -0.02em;
- line-height: 1.2;
-}
-
-.community-video-desc {
- margin-top: auto;
- color: var(--muted);
- font-size: 0.9rem;
- line-height: 1.55;
-}
-
-@keyframes theme-hint-pulse {
- 0%, 70%, 100% {
- opacity: 0;
- transform: scale(1);
- }
- 78% {
- opacity: 0.45;
- transform: scale(1.06);
- }
- 88% {
- opacity: 0;
- transform: scale(1.13);
- }
-}
-
-@keyframes theme-hint-dot {
- 0%, 70%, 100% {
- transform: translateX(0);
- }
- 78% {
- transform: translateX(2px);
- }
- 86% {
- transform: translateX(0);
- }
-}
-
-.section {
- padding-top: 5rem;
- padding-bottom: 5rem;
- border-top: 1px solid var(--line);
-}
-
-.contrast-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.75rem;
- margin-top: 1.75rem;
-}
-
-.contrast-grid article {
- min-height: 140px;
- padding: 1rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: transparent;
-}
-
-.contrast-grid span {
- display: block;
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.68rem;
- font-weight: 700;
- letter-spacing: 0.08em;
- text-transform: uppercase;
-}
-
-.contrast-grid p {
- margin: 0.7rem 0 0;
- color: var(--ink-soft);
- line-height: 1.55;
- font-size: 0.95rem;
-}
-
-.section-heading,
-.section-heading-wide {
- margin-bottom: 1.75rem;
-}
-
-.section-heading h2,
-.section-heading-wide h2,
-.final-cta h2 {
- font-size: clamp(1.8rem, 4vw, 3.2rem);
- max-width: 800px;
- font-family: var(--mono);
- font-weight: 400;
-}
-
-.section-heading-wide {
- display: grid;
- grid-template-columns: minmax(0, 1fr) minmax(280px, 0.48fr);
- gap: 2.5rem;
- align-items: end;
-}
-
-.why-section .section-heading-wide {
- align-items: start;
-}
-
-.why-section .section-heading-wide p {
- margin-top: 0.5rem;
-}
-
-.section-heading-wide p,
-.final-cta p {
- margin: 0;
- color: var(--muted);
- font-size: 1rem;
- line-height: 1.65;
-}
-
-.pillar-grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 0.75rem;
-}
-
-.pillar-card,
-.access-card {
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: transparent;
-}
-
-.pillar-card {
- min-height: 220px;
- padding: 1.25rem;
- display: flex;
- flex-direction: column;
-}
-
-.card-index {
- width: fit-content;
- border-radius: var(--radius-sm);
- background: var(--accent-soft);
- color: var(--accent);
- padding: 0.2rem 0.5rem;
- font-family: var(--mono);
- font-size: 0.68rem;
- font-weight: 700;
-}
-
-.pillar-card h3,
-.access-card h3 {
- margin: 1rem 0 0;
- color: var(--ink);
- letter-spacing: -0.02em;
- line-height: 1.1;
- font-size: 1.2rem;
- font-family: var(--mono);
- font-weight: 400;
-}
-
-.pillar-card p,
-.access-card p {
- margin: 0.75rem 0 0;
- color: var(--muted);
- line-height: 1.6;
- font-size: 0.95rem;
-}
-
-.access-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.75rem;
-}
-
-.access-card {
- position: relative;
- display: flex;
- flex-direction: column;
- min-height: 340px;
- overflow: hidden;
- padding: 1.1rem;
- background: var(--bg-elevated);
-}
-
-.access-card::before {
- content: "";
- position: absolute;
- inset: 0 0 auto;
- height: 3px;
- background: var(--accent);
-}
-
-.access-card:nth-child(2)::before {
- background: var(--green);
-}
-
-.access-card:nth-child(3)::before {
- background: var(--yellow);
-}
-
-.access-label {
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.68rem;
- font-weight: 700;
- letter-spacing: 0.14em;
- text-transform: uppercase;
-}
-
-.access-card h3 {
- margin-top: 0.85rem;
-}
-
-.access-card p {
- margin-top: 0.7rem;
-}
-
-.access-card pre {
- margin: auto 0 0;
- padding: 0.85rem;
- overflow: auto;
- border-radius: var(--radius-sm);
- background: var(--term-bg);
- color: var(--term-text);
- font-size: 0.78rem;
- line-height: 1.5;
- border: 1px solid var(--term-border);
-}
-
-.mobile-proof {
- display: grid;
- grid-template-columns: minmax(0, 0.82fr) minmax(320px, 1.18fr);
- align-items: center;
- gap: 2rem;
- margin-top: 2.4rem;
-}
-
-.mobile-copy h3 {
- margin: 0;
- max-width: 620px;
- color: var(--ink);
- font-size: clamp(1.7rem, 3.5vw, 2.8rem);
- letter-spacing: -0.03em;
- line-height: 1.05;
- font-family: var(--mono);
- font-weight: 400;
-}
-
-.mobile-copy p:not(.section-kicker) {
- margin: 1rem 0 0;
- max-width: 480px;
- color: var(--muted);
- font-size: 0.95rem;
- line-height: 1.6;
-}
-
-.mobile-shots {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 0.85rem;
- padding: 0.9rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-lg);
- background: var(--bg-elevated);
-}
-
-.mobile-proof figure {
- margin: 0;
- text-align: center;
-}
-
-.mobile-proof img {
- width: 100%;
- height: 340px;
- object-fit: cover;
- object-position: top;
- border-radius: var(--radius-md);
- border: 5px solid var(--term-bg);
- background: var(--term-bg);
-}
-
-.mobile-proof figcaption {
- margin-top: 0.5rem;
- color: var(--muted);
- font-size: 0.78rem;
- font-family: var(--mono);
-}
-
-.mobile-shout {
- grid-column: 1 / -1;
- margin: 0.1rem 0 0;
- color: var(--muted);
- font-size: 0.78rem;
- text-align: center;
-}
-
-.mobile-shout a {
- color: var(--muted);
- border-bottom: 1px solid var(--line);
-}
-
-.mobile-shout a:hover {
- color: var(--accent);
- border-color: var(--accent);
-}
-
-.inline-links {
- display: flex;
- flex-wrap: wrap;
- gap: 0.6rem;
- margin-top: 1.25rem;
-}
-
-.inline-links a {
- border: 1px solid var(--line-strong);
- border-radius: var(--radius-md);
- padding: 0.5rem 0.75rem;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.82rem;
- font-weight: 600;
-}
-
-.inline-links a:hover {
- border-color: var(--accent);
- color: var(--accent);
- background: var(--accent-soft);
-}
-
-.code-card {
- min-width: 0;
- border-radius: var(--radius-lg);
- background: var(--term-bg);
- border: 1px solid var(--line-strong);
- overflow: hidden;
-}
-
-.code-card pre {
- margin: 0;
- padding: 1.15rem;
- color: var(--term-text);
- overflow: auto;
- font-size: 0.82rem;
- line-height: 1.75;
-}
-
-.code-card .comment {
- color: var(--term-muted);
-}
-
-.code-card .cmd {
- color: var(--term-prompt);
- font-weight: 700;
-}
-
-.code-card .flag {
- color: var(--term-str);
-}
-
-.code-card .str {
- color: var(--term-cmd);
-}
-
-.table-wrap {
- overflow: auto;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: transparent;
-}
-
-table {
- width: 100%;
- border-collapse: collapse;
- min-width: 680px;
-}
-
-th,
-td {
- padding: 0.85rem 1rem;
- border-bottom: 1px solid var(--line);
- text-align: left;
-}
-
-th {
- color: var(--muted);
- font-size: 0.68rem;
- font-family: var(--mono);
- letter-spacing: 0.1em;
- text-transform: uppercase;
- font-weight: 700;
-}
-
-td {
- color: var(--ink-soft);
- font-size: 0.92rem;
-}
-
-tr:last-child td {
- border-bottom: 0;
-}
-
-th:last-child,
-td:last-child {
- color: var(--accent);
- font-weight: 700;
- background: var(--accent-soft);
-}
-
-.compare-cards {
- display: none;
-}
-
-.agent-grid {
- display: grid;
- grid-template-columns: repeat(8, minmax(0, 1fr));
- gap: 0.6rem;
-}
-
-.agent-card {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 0.5rem;
- min-height: 3rem;
- padding: 0.65rem 0.75rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
- color: var(--ink-soft);
- font-family: var(--mono);
- font-size: 0.78rem;
- font-weight: 600;
- line-height: 1;
- text-align: center;
- white-space: nowrap;
-}
-
-.agent-card .agent-icon {
- display: inline-block;
- width: 1.15rem;
- height: 1.15rem;
- flex: 0 0 auto;
- background-color: currentColor;
- opacity: 0.9;
- -webkit-mask-image: var(--agent-icon);
- -webkit-mask-size: contain;
- -webkit-mask-repeat: no-repeat;
- -webkit-mask-position: center;
- mask-image: var(--agent-icon);
- mask-size: contain;
- mask-repeat: no-repeat;
- mask-position: center;
-}
-
-.agent-more {
- color: var(--accent);
- background: var(--accent-soft);
- border-color: color-mix(in srgb, var(--accent) 32%, var(--line));
-}
-
-
-.integration-note {
- max-width: 680px;
- margin: 1.1rem 0 0;
- color: var(--muted);
- font-size: 0.95rem;
- line-height: 1.6;
-}
-
-.integration-note a {
- color: var(--accent);
- font-weight: 700;
- text-decoration: underline;
- text-decoration-thickness: 0.08em;
- text-underline-offset: 0.18em;
-}
-
-.final-cta {
- margin-top: 2rem;
- margin-bottom: 4rem;
- padding-top: 3.5rem;
- padding-bottom: 3.5rem;
- text-align: center;
- border-radius: var(--radius-lg);
- background: transparent;
- border: 1px solid var(--line);
-}
-
-.final-cta .section-kicker {
- justify-content: center;
-}
-
-.final-cta h2 {
- margin-inline: auto;
- max-width: 680px;
-}
-
-.final-cta p {
- max-width: 560px;
- margin: 1rem auto 0;
-}
-
-.footer {
- padding-top: 1.75rem;
- padding-bottom: 1.75rem;
- border-top: 1px solid var(--line);
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1rem;
- color: var(--muted);
- font-size: 0.85rem;
- font-family: var(--mono);
-}
-
-.footer div {
- display: flex;
- flex-wrap: wrap;
- gap: 1rem;
- justify-content: flex-end;
-}
-
-.footer .footer-social {
- display: flex;
- flex-wrap: wrap;
- gap: 0.45rem;
- justify-content: flex-end;
-}
-
-.footer-social a {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 2rem;
- height: 2rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- color: var(--muted);
- transition:
- color 120ms ease,
- border-color 120ms ease,
- background 120ms ease;
-}
-
-.footer-social a:hover {
- color: var(--accent);
- border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
- background: var(--accent-soft);
-}
-
-.footer-social svg {
- width: 1rem;
- height: 1rem;
- fill: currentColor;
-}
-
-.compare-hero {
- max-width: var(--max);
- min-height: auto;
- margin: 0 auto;
- padding: 5rem 1.25rem;
- grid-template-columns: minmax(0, 0.95fr) minmax(320px, 0.75fr);
- gap: 2rem;
- align-items: center;
- border-bottom: 0;
-}
-
-.compare-hero .hero-copy {
- max-width: 640px;
-}
-
-.compare-hero h1 {
- font-size: clamp(2.4rem, 5vw, 4rem);
-}
-
-.compare-claim-card {
- border: 1px solid var(--line);
- border-radius: var(--radius-lg);
- background: transparent;
- padding: clamp(1.25rem, 3vw, 1.75rem);
-}
-
-.compare-claim-card h2 {
- margin: 0;
- color: var(--ink);
- font-size: clamp(1.6rem, 3vw, 2.4rem);
- letter-spacing: -0.03em;
- line-height: 1.1;
- font-family: var(--mono);
- font-weight: 400;
-}
-
-.compare-checks {
- list-style: none;
- margin: 1.1rem 0 0;
- padding: 0;
- display: grid;
- gap: 0.55rem;
-}
-
-.compare-checks li {
- position: relative;
- padding-left: 1.4rem;
- color: var(--muted);
- line-height: 1.45;
- font-size: 0.92rem;
-}
-
-.compare-checks li::before {
- content: "→";
- position: absolute;
- left: 0;
- color: var(--accent);
- font-family: var(--mono);
- font-weight: 700;
-}
-
-.compare-section .section-heading-wide a,
-.compare-stack-section .section-heading-wide a {
- color: var(--accent);
- font-weight: 700;
- text-decoration: underline;
- text-decoration-thickness: 0.08em;
- text-underline-offset: 0.18em;
-}
-
-.comparison-matrix table {
- min-width: 900px;
-}
-
-.comparison-matrix th:last-child,
-.comparison-matrix td:last-child {
- color: var(--ink-soft);
- font-weight: inherit;
- background: transparent;
-}
-
-.comparison-matrix th:nth-child(2),
-.comparison-matrix td:nth-child(2) {
- color: var(--accent);
- font-weight: 700;
- background: var(--accent-soft);
-}
-
-.comparison-matrix td:first-child {
- color: var(--ink);
- font-weight: 600;
-}
-
-.differ-grid {
- display: grid;
- grid-template-columns: minmax(300px, 0.88fr) minmax(0, 1.12fr);
- gap: 0.75rem;
- align-items: stretch;
-}
-
-.intersection-card,
-.differ-list article {
- border: 1px solid var(--line);
- background: transparent;
-}
-
-.intersection-card {
- border-radius: var(--radius-lg);
- padding: clamp(1.25rem, 3vw, 1.75rem);
-}
-
-.intersection-card h3 {
- margin: 1rem 0 0;
- color: var(--ink);
- font-size: clamp(1.6rem, 3.5vw, 2.6rem);
- letter-spacing: -0.03em;
- line-height: 1.1;
- font-family: var(--mono);
- font-weight: 400;
-}
-
-.intersection-card p {
- margin: 1rem 0 0;
- color: var(--muted);
- font-size: 0.95rem;
- line-height: 1.65;
-}
-
-.intersection-pills {
- display: flex;
- flex-wrap: wrap;
- gap: 0.45rem;
- margin-top: 1.2rem;
-}
-
-.intersection-pills span {
- border: 1px solid var(--line);
- border-radius: var(--radius-sm);
- background: transparent;
- color: var(--accent);
- padding: 0.3rem 0.55rem;
- font-size: 0.72rem;
- font-family: var(--mono);
- font-weight: 700;
-}
-
-.differ-list {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 0.75rem;
-}
-
-.differ-list article {
- min-height: 190px;
- border-radius: var(--radius-md);
- padding: 1.1rem;
-}
-
-.differ-list article span {
- display: block;
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.68rem;
- font-weight: 700;
- letter-spacing: 0.08em;
- text-transform: uppercase;
-}
-
-.differ-list article h3 {
- margin: 0.85rem 0 0;
- color: var(--ink);
- font-size: 1.15rem;
- letter-spacing: -0.02em;
- line-height: 1.15;
- font-family: var(--mono);
- font-weight: 400;
-}
-
-.differ-list article p {
- margin: 0.7rem 0 0;
- color: var(--muted);
- line-height: 1.6;
- font-size: 0.92rem;
-}
-
-.one-liner-list {
- display: grid;
- gap: 0.6rem;
-}
-
-.one-liner-list article {
- display: grid;
- grid-template-columns: minmax(160px, 0.32fr) minmax(0, 1fr);
- gap: 1rem;
- align-items: start;
- padding: 0.85rem 1rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: transparent;
-}
-
-.one-liner-list strong {
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.8rem;
- font-weight: 700;
-}
-
-.one-liner-list span {
- color: var(--muted);
- line-height: 1.55;
- font-size: 0.92rem;
-}
-
-.compare-final-cta {
- margin-top: 0;
-}
-
-@media (max-width: 980px) {
- .hero {
- grid-template-columns: 1fr;
- }
-
- .hero-left {
- padding: 3rem 2rem;
- border-right: none;
- border-bottom: 1px solid var(--line);
- }
-
- .hero-right {
- padding: 3rem 2rem;
- }
-
- .hero-product-shot {
- max-width: 720px;
- }
-
- .section-heading-wide {
- grid-template-columns: 1fr;
- }
-
- .pillar-grid,
- .contrast-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-
- .community-video-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-
- .access-grid {
- grid-template-columns: repeat(3, minmax(0, 1fr));
- }
-
- .agent-grid {
- grid-template-columns: repeat(4, minmax(0, 1fr));
- }
-
- .mobile-proof,
- .differ-grid {
- grid-template-columns: 1fr;
- }
-
- .mobile-shots {
- max-width: 720px;
- margin-inline: auto;
- }
-
- .intersection-card {
- min-height: auto;
- }
-}
-
-@media (max-width: 720px) {
- .nav {
- padding-inline: 1rem;
- }
-
- .nav-menu {
- display: block;
- }
-
- .nav-links {
- display: none;
- }
-
- .nav-tools {
- display: none;
- }
-
- .section,
- .demo-section,
- .footer,
- .final-cta {
- padding-inline: 1rem;
- }
-
- .hero-left {
- padding: 2.5rem 1.25rem;
- }
-
- .hero-right {
- padding: 2rem 1.25rem;
- }
-
- .hero {
- min-height: auto;
- }
-
- .hero h1 {
- font-size: clamp(2.2rem, 11vw, 3rem);
- }
-
- .hero-lede {
- font-size: 0.95rem;
- }
-
- .install-card {
- border-radius: var(--radius-md);
- grid-template-columns: auto minmax(0, 1fr);
- }
-
- .install-card button {
- grid-column: 1 / -1;
- justify-self: start;
- }
-
- .demo-section {
- padding-bottom: 3rem;
- }
-
- .demo-video {
- border-radius: var(--radius-md);
- }
-
- .section {
- padding-top: 3rem;
- padding-bottom: 3rem;
- }
-
- .section-heading h2,
- .section-heading-wide h2,
- .final-cta h2 {
- font-size: clamp(1.6rem, 10vw, 2.4rem);
- }
-
- .pillar-grid,
- .contrast-grid,
- .community-video-grid,
- .access-grid,
- .differ-list {
- grid-template-columns: 1fr;
- }
-
- .agent-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-
- .compare-section .table-wrap {
- display: none;
- }
-
- .compare-cards {
- display: grid;
- gap: 0.6rem;
- }
-
- .compare-cards article {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.4rem;
- padding: 0.85rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: transparent;
- }
-
- .compare-cards h3 {
- grid-column: 1 / -1;
- margin: 0 0 0.2rem;
- color: var(--ink);
- font-size: 0.95rem;
- letter-spacing: -0.02em;
- font-family: var(--mono);
- }
-
- .compare-cards span {
- display: grid;
- gap: 0.2rem;
- padding: 0.55rem 0.45rem;
- border-radius: var(--radius-sm);
- background: var(--bg-elevated);
- color: var(--muted);
- font-size: 0.65rem;
- font-weight: 700;
- text-align: center;
- text-transform: uppercase;
- font-family: var(--mono);
- }
-
- .compare-cards b {
- color: var(--ink-soft);
- font-size: 0.82rem;
- text-transform: none;
- font-weight: 600;
- }
-
- .compare-cards .herdr {
- background: var(--accent-soft);
- color: var(--accent);
- }
-
- .compare-cards .herdr b {
- color: var(--accent);
- }
-
- .one-liner-list article {
- grid-template-columns: 1fr;
- }
-
- .pillar-card {
- min-height: auto;
- }
-
- .pillar-card p {
- margin-top: 0.85rem;
- }
-
- .access-card {
- min-height: auto;
- }
-
- .mobile-shots {
- grid-template-columns: 1fr;
- }
-
- .mobile-proof img {
- height: 300px;
- }
-
- .final-cta {
- border-radius: var(--radius-md);
- margin-bottom: 2.5rem;
- }
-
- .footer {
- flex-direction: column;
- align-items: flex-start;
- padding-bottom: 4.5rem;
- }
-
- .footer div {
- justify-content: flex-start;
- }
-
- .footer .footer-social {
- justify-content: flex-start;
- }
-}
-
-@media (max-width: 440px) {
- .button {
- width: 100%;
- }
-
- .hero-actions {
- width: 100%;
- }
-
- .hero-right {
- order: -1;
- display: flex;
- padding: 1.25rem 1rem 1.5rem;
- border-bottom: 1px solid var(--line);
- border-top: 0;
- }
-
- .hero-left {
- border-bottom: none;
- }
-
- .hero-product-shot {
- width: 100%;
- }
-
- .hero-product-shot figcaption {
- display: block;
- margin-top: 0.45rem;
- font-size: 0.68rem;
- }
-
- .herdr-ui-mock {
- grid-template-columns: 96px minmax(0, 1fr);
- aspect-ratio: 16 / 10;
- font-size: 0.38rem;
- border-radius: var(--radius-md);
- }
-
- .mock-sidebar-title,
- .mock-sidebar-row,
- .mock-agent-title {
- padding: 0.28rem 0.45rem;
- }
-
- .mock-space {
- gap: 0.3rem;
- padding: 0.3rem 0.45rem;
- }
-
- .mock-agent {
- gap: 0.3rem;
- padding: 0.24rem 0.45rem;
- }
-
- .mock-tabs {
- height: 1.05rem;
- }
-
- .mock-tabs span {
- min-width: 2.8rem;
- padding: 0.15rem 0.4rem;
- }
-
- .mock-panes {
- grid-template-columns: 1fr;
- gap: 0;
- padding: 0;
- }
-
- .mock-pane:nth-child(2) {
- display: none;
- }
-
- .mock-pane pre {
- margin: 0.35rem 0 0.45rem;
- }
-
- .mobile-proof,
- .mobile-shots {
- gap: 0.55rem;
- }
-
- .mobile-proof img {
- height: 260px;
- border-width: 4px;
- }
-}
-
-.content-shell {
- padding-bottom: 5rem;
-}
-
-.page-hero {
- max-width: var(--max);
- margin: 0 auto;
- padding: 5rem 1.25rem 2.25rem;
-}
-
-.page-hero-compact {
- max-width: 860px;
-}
-
-.page-hero h1 {
- max-width: 14ch;
- margin: 0;
- color: var(--ink);
- font-size: clamp(2.8rem, 7vw, 6rem);
- line-height: 0.92;
- letter-spacing: -0.07em;
-}
-
-.article-header h1 {
- max-width: 22ch;
- margin: 0;
- color: var(--ink);
- font-size: clamp(2rem, 4vw, 3.4rem);
- line-height: 1;
- letter-spacing: -0.055em;
-}
-
-.page-hero .hero-lede {
- max-width: 680px;
- color: var(--muted);
-}
-
-.section-narrow {
- max-width: 860px;
-}
-
-.post-list {
- display: grid;
-}
-
-.post-card {
- border-top: 1px solid var(--line);
-}
-
-.post-card:last-child {
- border-bottom: 1px solid var(--line);
-}
-
-.post-card-link {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1.5rem;
- padding: 1.45rem 0;
- text-decoration: none;
-}
-
-.post-card h2 {
- margin: 0;
- color: var(--ink);
- font-size: clamp(1.45rem, 3vw, 2.05rem);
- line-height: 1;
- letter-spacing: -0.055em;
- transition: color 0.16s ease;
-}
-
-.post-card p {
- max-width: 680px;
- margin: 0.55rem 0 0;
- color: color-mix(in srgb, var(--ink) 62%, var(--muted));
- line-height: 1.55;
-}
-
-.release-card-version {
- margin: 0 0 0.42rem !important;
- color: var(--accent) !important;
- font-family: var(--mono);
- font-size: 0.78rem;
- font-weight: 800;
- letter-spacing: 0.08em;
- text-transform: uppercase;
-}
-
-.post-card span {
- flex: 0 0 auto;
- color: var(--muted-2);
- font-family: var(--mono);
- font-size: 1.25rem;
- font-weight: 800;
- opacity: 0.55;
- transition:
- color 0.16s ease,
- opacity 0.16s ease,
- transform 0.16s ease;
-}
-
-.post-card:hover h2 {
- color: var(--accent);
-}
-
-.post-card:hover span {
- color: var(--accent);
- opacity: 1;
- transform: translateX(4px);
-}
-
-.text-link {
- display: inline-flex;
- align-items: center;
- flex: 0 0 auto;
- color: var(--accent);
- font-weight: 750;
- text-decoration: underline;
- text-decoration-thickness: 1px;
- text-underline-offset: 0.18em;
-}
-
-.post-meta {
- display: flex;
- flex-wrap: wrap;
- gap: 0.55rem;
- align-items: center;
- margin: 0 0 0.85rem;
- color: color-mix(in srgb, var(--ink) 58%, var(--muted));
- font-family: var(--mono);
- font-size: 0.78rem;
- font-weight: 700;
- letter-spacing: -0.03em;
- text-transform: uppercase;
-}
-
-.post-meta > * + *::before {
- content: "/";
- margin-right: 0.55rem;
- color: var(--line-strong);
-}
-
-.article-layout {
- position: relative;
- display: grid;
- grid-template-columns: minmax(8rem, 12rem) minmax(0, 860px);
- gap: clamp(2rem, 6vw, 4rem);
- align-items: start;
- padding-top: 4rem;
-}
-
-.article-shell {
- min-width: 0;
-}
-
-.article-toc {
- position: sticky;
- top: 6rem;
- padding-top: 0.35rem;
- color: color-mix(in srgb, var(--ink) 58%, var(--muted));
- font-family: var(--mono);
- font-size: 0.78rem;
-}
-
-.article-toc p {
- margin: 0 0 0.7rem;
- color: color-mix(in srgb, var(--ink) 42%, var(--muted));
- font-weight: 800;
- letter-spacing: 0.14em;
- text-transform: uppercase;
-}
-
-.article-toc nav {
- display: grid;
- gap: 0.55rem;
-}
-
-.article-toc a {
- color: color-mix(in srgb, var(--ink) 58%, var(--muted));
- line-height: 1.35;
- text-decoration: none;
-}
-
-.article-toc a:hover,
-.article-toc a[aria-current="true"] {
- color: var(--accent);
-}
-
-.article-header {
- margin-bottom: 2.35rem;
- padding-bottom: 2rem;
- border-bottom: 1px solid var(--line);
-}
-
-.article-header p:last-child {
- max-width: 680px;
- margin: 1.2rem 0 0;
- color: color-mix(in srgb, var(--ink) 68%, var(--muted));
- font-size: 1.18rem;
- line-height: 1.7;
-}
-
-.article-prose {
- color: var(--ink);
- font-size: 1.04rem;
- line-height: 1.82;
-}
-
-.article-prose > *:first-child {
- margin-top: 0;
-}
-
-.article-prose h1,
-.article-prose h2,
-.article-prose h3 {
- color: var(--ink);
- line-height: 1.05;
- letter-spacing: -0.04em;
-}
-
-.article-prose h1 {
- margin: 2.3rem 0 1rem;
- font-size: clamp(2rem, 5vw, 3.5rem);
-}
-
-.article-prose h2 {
- margin: 2.2rem 0 0.75rem;
- font-size: clamp(1.55rem, 3vw, 2.2rem);
-}
-
-.article-prose h3 {
- margin: 1.7rem 0 0.65rem;
- font-size: 1.25rem;
-}
-
-.article-prose p,
-.article-prose ul,
-.article-prose ol {
- margin: 1rem 0;
-}
-
-.article-prose ul,
-.article-prose ol {
- padding-left: 1.35rem;
-}
-
-.article-prose li + li {
- margin-top: 0.42rem;
-}
-
-.article-prose blockquote {
- margin: 1.2rem 0;
- border-left: 2px solid color-mix(in srgb, var(--accent) 72%, var(--line));
- border-radius: var(--radius-sm);
- background: color-mix(in srgb, var(--bg-elevated) 46%, transparent);
- padding: 0.72rem 0.95rem;
- color: color-mix(in srgb, var(--ink) 76%, var(--muted));
- font-size: 1.06rem;
- font-weight: 560;
- line-height: 1.7;
-}
-
-.article-prose blockquote p {
- margin: 0;
-}
-
-.article-prose a {
- color: var(--accent);
- font-weight: 700;
- text-decoration: underline;
- text-decoration-thickness: 1px;
- text-underline-offset: 0.18em;
-}
-
-.article-prose code {
- border: 1px solid var(--line);
- border-radius: var(--radius-sm);
- background: var(--bg-elevated);
- color: var(--ink);
- padding: 0.08rem 0.28rem;
- font-size: 0.9em;
-}
-
-.article-prose pre {
- overflow-x: auto;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
- color: var(--ink);
- padding: 1rem;
-}
-
-.article-prose pre code {
- border: 0;
- background: transparent;
- color: inherit;
- padding: 0;
-}
-
-.article-prose .expressive-code .frame {
- border-color: var(--line) !important;
- background: var(--bg-elevated) !important;
- border-radius: var(--radius-md) !important;
- overflow: hidden;
-}
-
-.article-prose .expressive-code .frame figcaption.header {
- display: none !important;
-}
-
-.article-prose .expressive-code pre {
- margin: 0 !important;
- border: 0 !important;
- border-radius: 0 !important;
- background: var(--bg-elevated) !important;
- color: var(--ink) !important;
-}
-
-.article-prose .expressive-code .code,
-.article-prose .expressive-code .code span {
- color: var(--ink) !important;
-}
-
-.release-shell {
- max-width: 900px;
-}
-
-.release-header h1 {
- max-width: 820px;
- font-size: clamp(1.9rem, 3.5vw, 3.1rem);
- line-height: 1.04;
-}
-
-.release-prose h2 {
- margin-top: 3rem;
-}
-
-.release-prose h3 {
- margin-top: 1.9rem;
- padding-top: 1.4rem;
- border-top: 1px solid var(--line);
-}
-
-.release-media {
- margin: 1.6rem 0 2.4rem;
-}
-
-.release-media video {
- display: block;
- width: 100%;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
-}
-
-.release-media figcaption {
- margin-top: 0.75rem;
- color: color-mix(in srgb, var(--ink) 52%, var(--muted));
- font-family: var(--mono);
- font-size: 0.78rem;
- line-height: 1.5;
-}
-
-.release-video-placeholder {
- display: grid;
- min-height: 19rem;
- place-items: center;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background:
- linear-gradient(135deg, color-mix(in srgb, var(--accent) 10%, transparent), transparent 42%),
- var(--bg-elevated);
- color: var(--ink);
- padding: 2rem;
- text-align: center;
-}
-
-.release-video-placeholder span {
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.74rem;
- font-weight: 800;
- letter-spacing: 0.12em;
- text-transform: uppercase;
-}
-
-.release-video-placeholder strong {
- display: block;
- margin-top: 0.6rem;
- font-size: clamp(1.5rem, 4vw, 2.6rem);
- line-height: 1;
- letter-spacing: -0.055em;
-}
-
-.release-video-placeholder code {
- margin-top: 1rem;
- overflow-wrap: anywhere;
-}
-
-.author-card {
- display: flex;
- align-items: center;
- gap: 1.1rem;
- margin-top: 3.5rem;
- padding: 1.4rem 1.5rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-lg);
- background: color-mix(in srgb, var(--bg-elevated) 60%, transparent);
-}
-
-.author-photo {
- flex: none;
- width: 72px;
- height: 72px;
- border-radius: 50%;
- object-fit: cover;
- border: 1px solid var(--line);
-}
-
-.author-body {
- min-width: 0;
-}
-
-.author-name {
- margin: 0;
- color: var(--ink);
- font-size: 1.05rem;
- font-weight: 800;
- letter-spacing: -0.01em;
-}
-
-.author-role {
- margin: 0.1rem 0 0;
- color: color-mix(in srgb, var(--ink) 56%, var(--muted));
- font-family: var(--mono);
- font-size: 0.8rem;
-}
-
-.author-links {
- display: flex;
- flex-wrap: wrap;
- gap: 0.55rem;
- margin-top: 0.8rem;
-}
-
-.author-links a {
- display: inline-flex;
- align-items: center;
- gap: 0.4rem;
- padding: 0.35rem 0.7rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- color: color-mix(in srgb, var(--ink) 78%, var(--muted));
- font-size: 0.82rem;
- font-weight: 700;
- text-decoration: none;
- transition: color 0.15s ease, border-color 0.15s ease;
-}
-
-.author-links a:hover {
- color: var(--accent);
- border-color: color-mix(in srgb, var(--accent) 60%, var(--line));
-}
-
-.author-links svg {
- flex: none;
-}
-
-@media (max-width: 1040px) {
- .article-layout {
- display: block;
- max-width: 860px;
- }
-
- .article-toc {
- display: none;
- }
-}
-
-@media (prefers-reduced-motion: reduce) {
- *,
- *::before,
- *::after {
- scroll-behavior: auto !important;
- animation-duration: 0.001ms !important;
- animation-iteration-count: 1 !important;
- }
-
- .theme-hint::after {
- display: none;
- }
-}
-
-/* ===== herd mock: interactive views, agent panes, attach animation ===== */
-
-.mock-view {
- display: none;
- min-height: 0;
- grid-template-rows: auto minmax(0, 1fr);
-}
-
-.mock-view.active {
- display: grid;
-}
-
-.herdr-ui-mock .mock-main {
- grid-template-rows: minmax(0, 1fr);
-}
-
-.mock-panes.single {
- grid-template-columns: minmax(0, 1fr);
-}
-
-/* TUI panes pin their prompt/status area to the bottom, like the real thing */
-.mock-pane.tui {
- display: flex;
- flex-direction: column;
-}
-
-.mock-pane.tui .tui-bottom {
- margin-top: auto;
-}
-
-.herdr-ui-mock .mock-space,
-.herdr-ui-mock .mock-agent,
-.herdr-ui-mock .mock-tabs span {
- cursor: pointer;
-}
-
-.herdr-ui-mock .mock-space:hover,
-.herdr-ui-mock .mock-agent:hover {
- background: var(--term-active-bg);
-}
-
-.mock-view .mock-panes {
- display: none;
-}
-
-.mock-view .mock-panes.active {
- display: grid;
-}
-
-.cc-head b {
- color: var(--term-text);
-}
-
-.cc-mark,
-.cc-working {
- color: #d97757;
-}
-
-.cc-bullet {
- color: #d97757;
-}
-
-/* Claude Code header logo + status footer — colors hardcoded to match the
- real agent UI, not the site theme (the pane renders the agent, not herdr) */
-.cc-header {
- display: flex;
- gap: 0.6em;
- align-items: center;
-}
-
-.herdr-ui-mock .cc-logo-art {
- margin: 0;
- color: #d97757;
- line-height: 1;
- white-space: pre;
- font-family: var(--mono);
-}
-
-.cc-header-text {
- min-width: 0;
-}
-
-.cc-header-text > div {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.cc-status {
- white-space: nowrap;
- overflow: hidden;
-}
-
-.cc-file {
- color: #b1b9f9;
-}
-
-.cc-cyan {
- color: #4ec9d4;
-}
-
-.cc-yellow {
- color: #d7ba7d;
-}
-
-.cc-coral {
- color: #ff6b80;
-}
-
-.cc-gy {
- color: var(--term-dim);
-}
-
-.cx-bullet {
- color: var(--accent);
-}
-
-.cc-rule {
- margin: 0.5rem 0;
- border-top: 1px solid var(--term-border);
-}
-
-.cc-permission {
- margin-top: 0.55rem;
- border: 1px solid var(--red);
- padding: 0.5rem 0.6rem;
-}
-
-/* opencode pane: brand gold/purple, outline badge, walled input box */
-.oc-y {
- color: #d9b66b;
-}
-
-.oc-purple {
- color: #b481d4;
-}
-
-.oc-badge {
- display: inline-block;
- width: 0.8em;
- height: 0.8em;
- vertical-align: -0.05em;
- border: 1px solid var(--term-muted);
-}
-
-.oc-input {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- min-height: 4.6em;
- margin-top: 0.3em;
- border-left: 0.28em solid #b481d4;
- border-bottom: 0.18em solid var(--term-border);
- background: var(--term-active-bg);
- padding: 0.4em 0.6em;
-}
-
-.oc-status {
- display: flex;
- justify-content: flex-end;
- margin-top: 0.35em;
-}
-
-.cc-permission .sel {
- color: var(--accent);
- font-weight: 700;
-}
-
-.herdr-ui-mock .dim {
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-
-/* sidebar rows must scale with the mock's clamped font size */
-.herdr-ui-mock .mock-sidebar-title {
- padding: 0.55em 1.1em;
-}
-
-.herdr-ui-mock .mock-space {
- padding: 0.55em 1.1em;
- gap: 0.7em;
-}
-
-.herdr-ui-mock .mock-sidebar-row,
-.herdr-ui-mock .mock-agent-title {
- padding: 0.45em 1.1em;
-}
-
-.herdr-ui-mock .mock-agent {
- padding: 0.38em 1.1em;
- gap: 0.6em;
-}
-
-.herdr-ui-mock .mock-space small,
-.herdr-ui-mock .mock-agent small {
- margin-top: 0.18em;
-}
-
-/* attach: sidebar populates once on load; view switches fade without movement */
-@keyframes mock-attach {
- from {
- opacity: 0;
- transform: translateY(5px);
- }
- to {
- opacity: 1;
- transform: none;
- }
-}
-
-@keyframes mock-swap {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}
-
-.herdr-ui-mock .mock-sidebar > * {
- animation: mock-attach 0.3s ease backwards;
-}
-
-.herdr-ui-mock .mock-sidebar > *:nth-child(1) { animation-delay: 0.05s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(2) { animation-delay: 0.12s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(3) { animation-delay: 0.19s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(4) { animation-delay: 0.26s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(6) { animation-delay: 0.33s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(7) { animation-delay: 0.4s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(8) { animation-delay: 0.47s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(9) { animation-delay: 0.54s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(10) { animation-delay: 0.61s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(11) { animation-delay: 0.68s; }
-.herdr-ui-mock .mock-sidebar > *:nth-child(12) { animation-delay: 0.75s; }
-
-.mock-view.active .mock-panes.active .mock-pane {
- animation: mock-swap 0.18s ease backwards;
-}
-
-@media (prefers-reduced-motion: reduce) {
- .herdr-ui-mock .mock-sidebar > *,
- .mock-view.active .mock-tabs,
- .mock-view.active .mock-pane {
- animation: none;
- }
-}
-
-/* Homepage marketplace teaser */
-.marketplace-teaser {
- display: block;
- padding-block: 4.5rem;
- border-bottom: 1px solid var(--line);
-}
-
-.marketplace-teaser-top {
- display: grid;
- grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
- gap: 3rem;
- align-items: center;
-}
-
-.marketplace-teaser-install {
- display: grid;
- gap: 0.55rem;
- align-content: center;
-}
-
-.marketplace-install-output {
- margin: 0;
- padding-inline: 0.9rem;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.82rem;
-}
-
-.marketplace-install-note {
- margin: 0;
- padding-inline: 0.9rem;
- color: var(--muted-2);
- font-family: var(--mono);
- font-size: 0.75rem;
-}
-
-@media (max-width: 50rem) {
- .marketplace-teaser-top {
- grid-template-columns: 1fr;
- gap: 2rem;
- }
-}
-
-.marketplace-teaser-copy h2 {
- margin: 0;
- color: var(--ink);
- font-family: var(--mono);
- font-weight: 400;
- letter-spacing: -0.04em;
- line-height: 1.05;
- font-size: clamp(1.9rem, 3.4vw, 2.8rem);
-}
-
-.marketplace-teaser-lede {
- max-width: 30rem;
- margin: 1.1rem 0 0;
- color: var(--ink-soft);
- font-size: clamp(1rem, 1.6vw, 1.12rem);
- line-height: 1.6;
-}
-
-.marketplace-teaser-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 0.75rem;
- margin-top: 2.5rem;
-}
-
-@media (max-width: 68rem) {
- .marketplace-teaser-grid {
- grid-template-columns: 1fr 1fr;
- }
-}
-
-.mp-chip {
- display: grid;
- gap: 0.3rem;
- padding: 1rem 1.1rem;
- background: var(--bg-elevated);
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- text-decoration: none;
- transition: border-color 0.12s ease, transform 0.12s ease;
-}
-
-.mp-chip:hover {
- border-color: var(--accent);
- transform: translateX(2px);
-}
-
-.mp-chip-name {
- color: var(--ink);
- font-family: var(--mono);
- font-size: 0.9rem;
- font-weight: 600;
-}
-
-.mp-chip-desc {
- color: var(--ink-soft);
- font-size: 0.85rem;
- line-height: 1.45;
-}
-
-.mp-chip-meta {
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.75rem;
-}
-
-@media (max-width: 50rem) {
- .marketplace-teaser {
- padding-block: 3.5rem;
- }
-
- .marketplace-teaser-grid {
- grid-template-columns: 1fr;
- }
-}
-
-/* What you get: balanced capability grid + code card */
-.capability-section .section-heading-wide {
- align-items: end;
-}
-
-.capability-body {
- display: grid;
- grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
- gap: 2rem;
- align-items: start;
- margin-top: 2.25rem;
-}
-
-.capability-cards {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 0.75rem;
-}
-
-.capability-cards article {
- padding: 1.1rem 1.2rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- background: var(--bg-elevated);
-}
-
-.capability-cards h3 {
- margin: 0;
- color: var(--ink);
- font-family: var(--mono);
- font-weight: 600;
- font-size: 0.92rem;
-}
-
-.capability-cards p {
- margin: 0.5rem 0 0;
- color: var(--ink-soft);
- font-size: 0.85rem;
- line-height: 1.5;
-}
-
-@media (max-width: 50rem) {
- .capability-body {
- grid-template-columns: 1fr;
- gap: 1.5rem;
- }
-}
diff --git a/website/favicon.ico b/website/favicon.ico
deleted file mode 100644
index fe1d81c0..00000000
--- a/website/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/website/index.html b/website/index.html
deleted file mode 100644
index cf8dd79a..00000000
--- a/website/index.html
+++ /dev/null
@@ -1,786 +0,0 @@
-<!doctype html>
-<html lang="en" data-palette="catppuccin" data-mode="ink">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>Herdr: the runtime coding agents run on</title>
- <meta
- name="description"
- content="Herdr is the runtime your coding agents live on. It holds real terminals open on your laptop, your desktop or a box you rent, so the work survives the lid closing — and you can attach again from anything with a keyboard."
- />
- <meta name="theme-color" content="#17171a" />
- <link rel="canonical" href="https://herdr.dev/" />
-
- <meta property="og:type" content="website" />
- <meta property="og:site_name" content="Herdr" />
- <meta property="og:title" content="Herdr: the runtime coding agents run on" />
- <meta
- property="og:description"
- content="Run them anywhere. Leave them running. Herdr holds real terminals open so your agents keep working when you close the laptop, and gets you back in from any tty."
- />
- <meta property="og:url" content="https://herdr.dev/" />
- <meta
- property="og:image"
- content="https://herdr.dev/assets/og-card-v9.png"
- />
- <meta property="og:image:width" content="1200" />
- <meta property="og:image:height" content="630" />
- <meta property="og:image:alt" content="Herdr — run them anywhere, leave them running." />
- <script type="application/ld+json">
- {
- "@context": "https://schema.org",
- "@type": "WebPage",
- "url": "https://herdr.dev/",
- "primaryImageOfPage": "https://herdr.dev/assets/og-card-v9.png"
- }
- </script>
-
- <meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:title" content="Herdr: the runtime coding agents run on" />
- <meta
- name="twitter:description"
- content="Run them anywhere. Leave them running. Herdr holds real terminals open so your agents keep working when you close the laptop."
- />
- <meta
- name="twitter:image"
- content="https://herdr.dev/assets/og-card-v9.png"
- />
- <meta name="twitter:image:alt" content="Herdr — run them anywhere, leave them running." />
-
- <link rel="icon" href="/favicon.ico" sizes="48x48" />
- <link rel="icon" type="image/png" sizes="192x192" href="/assets/favicon.png" />
- <link rel="apple-touch-icon" href="/assets/logo.png" />
- <link
- rel="preload"
- href="/assets/jbm.woff2?v=2"
- as="font"
- type="font/woff2"
- crossorigin
- />
- <link rel="preconnect" href="https://fonts.googleapis.com" />
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
- <link href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
- <script>
- /* Ground selection, shared with the docs.
- Starlight's `starlight-theme` key is the single source of truth,
- so a choice made in docs carries to the marketing pages and back.
- It stores dark | light | auto; we deliberately treat `auto` as
- dark, because the default here is a presentation decision and
- must not follow the reader's OS. The mock palette follows the
- ground: solarized-light on paper, catppuccin on ink. */
- window.herdrGround = {
- read: function () {
- try {
- return localStorage.getItem("starlight-theme") === "light" ? "paper" : "ink";
- } catch (e) {
- return "ink";
- }
- },
- apply: function (mode) {
- var root = document.documentElement;
- root.setAttribute("data-mode", mode);
- root.setAttribute("data-palette", mode === "paper" ? "solarized-light" : "catppuccin");
- return mode;
- },
- save: function (mode) {
- try {
- localStorage.setItem("starlight-theme", mode === "paper" ? "light" : "dark");
- } catch (e) {}
- },
- };
- window.herdrGround.apply(window.herdrGround.read());
- </script>
- <link rel="stylesheet" href="/css/style.css?v=59" />
- <link rel="stylesheet" href="/css/site.css?v=64" />
- </head>
- <body class="site">
- <div class="hd-frame">
-
- <nav class="hd-nav">
- <a class="lock" href="/"><span class="ram"></span><b>herdr</b></a>
- <div class="sp"></div>
- <a class="lnk" href="/docs/">Docs</a>
- <a class="lnk" href="/plugins/">Plugins</a>
- <a class="lnk" href="/blog/">Blog</a>
- <a class="lnk" href="/compare/">Compare</a>
- <a class="ico wide" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub — star count">
- <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" /></svg>
- <b data-stars><!--N_STARS--></b>
- </a>
- <a class="ico" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" /></svg>
- </a>
- <div class="mode">
- <button type="button" data-ground="ink" aria-pressed="true">ink</button>
- <button type="button" data-ground="paper" aria-pressed="false">paper</button>
- </div>
- <a class="btn" href="#install">Install</a>
- <button type="button" class="menu" id="nav-menu" aria-expanded="false" aria-controls="nav-sheet" aria-label="Menu">
- <span></span><span></span><span></span>
- </button>
- </nav>
-
- <div class="sheet" id="nav-sheet">
- <a href="/docs/">Docs</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- <a href="/compare/">Compare</a>
- <a href="https://x.com/herdrdev">@herdrdev</a>
- <div class="sheet-ground">
- <span>Ground</span>
- <div class="mode">
- <button type="button" data-ground="ink" aria-pressed="true">ink</button>
- <button type="button" data-ground="paper" aria-pressed="false">paper</button>
- </div>
- </div>
- </div>
-
- <header class="hd-hero">
- <span class="ram ghost"></span>
- <div class="in">
- <div class="hd-eyebrow"><s></s>the agent runtime</div>
- <h1>Run them <em>anywhere.</em> Leave them running.</h1>
- <p class="lede">Herdr is the runtime your coding agents live on — laptop, desktop, or a box you rent. It holds real terminals open so the work survives the lid closing, and <b>gets you back in from anything with a keyboard.</b></p>
- <div class="go">
- <div class="hd-cmd">
- <code id="install-cmd"><b>$</b>curl -fsSL https://herdr.dev/install.sh | sh</code>
- <button type="button" id="copy-btn" aria-label="Copy install command">copy</button>
- </div>
- </div>
- <div class="meta">macOS · Linux · Windows · Apache 2.0 &nbsp;—&nbsp; <a href="/docs/install/">windows, homebrew, nix and manual install →</a></div>
- <div class="meta yc-meta"><a class="yc" href="/blog/herdr-is-joining-y-combinator/">backed by <img src="/assets/yc-logo.svg" alt="Y" width="13" height="13" /> Combinator</a></div>
- </div>
- </header>
-
- <div class="strip">
- <a class="stat" href="https://github.com/herdrdev/herdr" data-count>
- <b id="n-stars"><!--N_STARS--></b>
- <span>
- <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.6l2.9 5.9 6.5.95-4.7 4.6 1.1 6.45L12 17.45 6.2 20.5l1.1-6.45-4.7-4.6 6.5-.95z"/></svg>
- github stars <i class="live"></i>
- </span>
- </a>
- <a class="stat" href="https://github.com/herdrdev/herdr/releases" data-count>
- <b id="n-installs"><!--N_INSTALLS--></b>
- <span>
- <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3v10m0 0l-4-4m4 4l4-4M4 17v3h16v-3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square"/></svg>
- installs to date
- </span>
- </a>
- <a class="stat" href="/plugins/" data-count>
- <b id="n-plugins"><!--N_PLUGINS--></b>
- <span>
- <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 3h8v8H3zM13 3h8v8h-8zM3 13h8v8H3zM13 13h8v8h-8z" fill="none" stroke="currentColor" stroke-width="2"/></svg>
- community plugins
- </span>
- </a>
- <a class="stat" href="/docs/agents/" data-count>
- <b><!--N_AGENTS--></b>
- <span>
- <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6l6 6-6 6M13 18h7" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square"/></svg>
- agent CLIs detected
- </span>
- </a>
- </div>
-
- <section class="fig">
- <div class="fighd">
- <span>the herd, from a client that isn't there</span>
- <span class="r">click an agent</span>
- </div>
- <div class="plate">
- <figure class="hero-product-shot">
- <div
- class="herdr-ui-mock"
- id="herd-mock"
- role="img"
- aria-label="Interactive Herdr session mock with workspaces, tabs, agent states, and terminal panes running Claude Code and Codex"
- >
- <aside class="mock-sidebar">
- <div class="mock-sidebar-half">
- <div class="mock-sidebar-title">spaces</div>
- <div class="mock-space active" data-ws="herdr">
- <span class="mock-dot dot-working"></span>
- <div><strong>herdr</strong><small>master</small></div>
- </div>
- <div class="mock-space" data-ws="web-dashboard">
- <span class="mock-dot dot-blocked"></span>
- <div><strong>web-dashboard</strong><small>feat/usage-charts</small></div>
- </div>
- <div class="mock-space" data-ws="data-pipeline">
- <span class="mock-dot dot-done"></span>
- <div><strong>data-pipeline</strong><small>backfill/events-v2</small></div>
- </div>
- </div>
- <div class="mock-sidebar-half mock-sidebar-agents">
- <div class="mock-agent-title"><span>agents</span><span>grouped</span></div>
- <div class="mock-agent working active" data-agent="herdr" data-kind="claude" data-ws-link="herdr" data-tab-link="main"><span>●</span><div><strong>herdr</strong><small>working · claude</small></div></div>
- <div class="mock-agent" data-agent="explore" data-kind="opencode" data-ws-link="herdr" data-tab-link="opencode"><span>○</span><div><strong>explore</strong><small>idle · opencode</small></div></div>
- <div class="mock-agent blocked" data-agent="web-dashboard" data-kind="claude" data-ws-link="web-dashboard" data-tab-link="main"><span>◉</span><div><strong>web-dashboard</strong><small>blocked · claude</small></div></div>
- <div class="mock-agent done" data-agent="data-pipeline" data-kind="codex" data-ws-link="data-pipeline" data-tab-link="main"><span>●</span><div><strong>data-pipeline</strong><small>done · codex</small></div></div>
- </div>
- </aside>
- <section class="mock-main">
- <div class="mock-view active" data-view="herdr">
- <div class="mock-tabs">
- <span data-tab="opencode">opencode</span><span class="active" data-tab="main">herdr</span><span>+</span>
- </div>
- <div class="mock-panes active" data-tab="main">
- <div class="mock-pane focused tui" data-title="claude">
- <div class="cc-header">
- <pre class="cc-logo-art"> ▐▛███▜▌
-▝▜█████▛▘
- ▘▘ ▝▝</pre>
- <div class="cc-header-text">
- <div><b>Claude Code</b> <span class="dim">v2.1.198</span></div>
- <div class="dim">Fable 5 with high effort · Claude Max</div>
- <div class="dim">~/Projects/herdr/website</div>
- </div>
- </div>
- <br />
- <div><b>❯</b> make the herdr.dev hero mock look exactly like real claude code</div>
- <br />
- <div><span class="cc-bullet">●</span> Ha. I read the real pane over the socket — the mock was on v2.1.168, Claude Code is <span class="cc-file">v2.1.198</span> now. Missing the logo block and the whole rate-limit row.</div>
- <br />
- <div><span class="cc-bullet">●</span> Plan:</div>
- <div class="dim">&nbsp;&nbsp;· index.html — swap ✻ for the real ▐▛███▜▌ mark, bump the version</div>
- <div class="dim">&nbsp;&nbsp;· css/style.css — coral bypass line, add the 5h / Week bars</div>
- <br />
- <div><b>❯</b> perfect. and make the dialogue about this, obviously</div>
- <br />
- <div><span class="cc-working"><span class="braille-spinner">⠋</span> Baking…</span> <span class="dim">(<span id="cc-timer">13m 36s</span> · esc to interrupt)</span></div>
- <div class="tui-bottom">
- <div class="cc-rule"></div>
- <div><b>❯</b> <span class="cursor"></span></div>
- <div class="cc-rule"></div>
- <div class="cc-status">&nbsp;&nbsp;<span class="cc-cyan">~/Projects/herdr/website</span><span class="cc-gy"> &gt; </span><span class="cc-yellow">master *</span><span class="green"> ↑1</span><span class="cc-gy"> &gt; ctx ──────── </span><span class="green">3%</span><span class="cc-gy"> 31k/1M</span></div>
- <div class="cc-status">&nbsp;&nbsp;<span class="cc-coral">⏵⏵ bypass permissions on</span> <span class="dim">(shift+tab to cycle)</span></div>
- </div>
- </div>
- <div class="mock-pane" data-title="bun">
- <div class="mock-prompt"><span>~/Projects/herdr</span> <em>master</em></div>
- <div><b>❯</b> <span class="cmd">bun</span> run dev</div>
- <div class="dim">$ node scripts/prepare-docs.mjs && astro dev</div>
- <div><span class="time">02:10:44</span> <span class="blue">[types]</span> Generated 0ms</div>
- <div><span class="time">02:10:44</span> <span class="blue">[content]</span> Synced content</div>
- <br />
- <div><span class="badge">astro</span> <span class="green">v5.18.1</span> ready in 668 ms</div>
- <br />
- <div class="url-line">┃ Local&nbsp;&nbsp; <span>http://localhost:4321/</span></div>
- <div class="dim"> Network&nbsp; use --host to expose</div>
- <br />
- <div><span class="time">02:10:44</span> <span class="green">watching for file changes...</span></div>
- </div>
- </div>
- <div class="mock-panes single" data-tab="opencode">
- <div class="mock-pane focused tui">
- <div class="oc-y">+ Thought: 468ms</div>
- <br />
- <div><span class="dim">→</span> Read src/main.rs</div>
- <br />
- <div class="oc-y">+ Thought: 292ms</div>
- <br />
- <div>This is <span class="oc-y">src/main.rs</span> — the entry point for <b>herdr</b>. Here's what it does:</div>
- <br />
- <div><span class="blue">1.</span> Arg parsing — <span class="oc-y">session::configure_from_args</span>, then remote args for the SSH bridge.</div>
- <div><span class="blue">2.</span> Subcommand dispatch — <span class="oc-y">server</span>, <span class="oc-y">client</span>, <span class="oc-y">update</span> — each returns early.</div>
- <div><span class="blue">3.</span> Session mode — <span class="oc-y">auto_detect_launch()</span> connects to a running server or spawns one.</div>
- <br />
- <div class="dim"><span class="oc-badge"></span>&nbsp; Build · MiMo V2.5 Free · 16.6s</div>
- <div class="tui-bottom">
- <div class="oc-input">
- <div><span class="cursor"></span></div>
- <div class="dim"><span class="oc-purple">Build</span> · MiMo V2.5 Free OpenCode Zen</div>
- </div>
- <div class="oc-status"><span class="dim">25.2K (13%)&nbsp;&nbsp;ctrl+p commands</span></div>
- </div>
- </div>
- </div>
- </div>
- <div class="mock-view" data-view="web-dashboard">
- <div class="mock-tabs">
- <span class="active" data-tab="main">claude</span><span data-tab="logs">dev server</span><span>+</span>
- </div>
- <div class="mock-panes single active" data-tab="main">
- <div class="mock-pane focused tui">
- <div class="cc-header">
- <pre class="cc-logo-art"> ▐▛███▜▌
-▝▜█████▛▘
- ▘▘ ▝▝</pre>
- <div class="cc-header-text">
- <div><b>Claude Code</b> <span class="dim">v2.1.198</span></div>
- <div class="dim">Fable 5 with high effort · Claude Max</div>
- <div class="dim">~/Projects/web-dashboard</div>
- </div>
- </div>
- <br />
- <div><b>❯</b> finish the usage chart and ship it to staging</div>
- <br />
- <div><span class="cc-bullet">●</span> Wrote src/components/UsageChart.tsx — stacked area, empty state, and the tooltip you asked for.</div>
- <br />
- <div><span class="cc-bullet">●</span> Typecheck and build are clean, 41.2 kB gzipped. Ready to push to staging.</div>
- <div class="tui-bottom">
- <div class="cc-permission">
- <div><b>Bash command</b></div>
- <div><span class="cmd">bunx</span> wrangler deploy --env staging</div>
- <div class="dim">Deploy the dashboard to the staging environment</div>
- <br />
- <div>Do you want to proceed?</div>
- <div class="sel">❯ 1. Yes</div>
- <div class="dim">&nbsp;&nbsp;2. No, and tell Claude what to do differently (esc)</div>
- </div>
- </div>
- </div>
- </div>
- <div class="mock-panes single" data-tab="logs">
- <div class="mock-pane focused">
- <div class="mock-prompt"><span>~/Projects/web-dashboard</span> <em>feat/usage-charts</em></div>
- <div><b>❯</b> <span class="cmd">bun</span> run dev</div>
- <div class="dim">VITE v6.3.1 ready in 412 ms</div>
- <div><span class="dim">Local</span> <span class="blue">http://localhost:5173/</span></div>
- <div><span class="time">02:30:58</span> <span class="green">hmr update</span> /src/components/UsageChart.tsx</div>
- <div><span class="time">02:31:04</span> <span class="green">hmr update</span> /src/styles/chart.css</div>
- <div><span class="time">02:31:09</span> <span class="dim">page reload</span> src/routes/usage.tsx</div>
- <div><span class="time">02:31:15</span> <span class="red">WARN</span> chunk "charts" is 512 kB after minification</div>
- <div><span class="time">02:31:18</span> <span class="green">hmr update</span> /src/components/UsageChart.tsx</div>
- <div><span class="time">02:31:24</span> <span class="green">hmr update</span> /src/components/Tooltip.tsx</div>
- <div><span class="time">02:31:33</span> <span class="dim">✓ built in</span> 1.94s</div>
- </div>
- </div>
- </div>
- <div class="mock-view" data-view="data-pipeline">
- <div class="mock-tabs">
- <span class="active" data-tab="main">codex</span><span data-tab="server">backfill</span><span>+</span>
- </div>
- <div class="mock-panes single active" data-tab="main">
- <div class="mock-pane focused tui">
- <div><span class="cx-bullet">•</span> <b>Explored</b></div>
- <div class="dim">&nbsp;&nbsp;└ Read jobs/backfill_events.py</div>
- <br />
- <div><span class="cx-bullet">•</span> <b>Ran</b></div>
- <div class="dim">&nbsp;&nbsp;└ uv run pytest tests/test_backfill.py</div>
- <div class="dim">&nbsp;&nbsp;└ 14 passed · 0 failed · 41.3s</div>
- <br />
- <div><span class="cx-bullet">•</span> Checkpointing works, so the job resumes from the last committed offset instead of restarting. The backfill in the next tab has been running for six hours and is unaffected by your laptop.</div>
- <br />
- <div><span class="cx-bullet">•</span> Next I can add the p95 lag alert to the nightly run. Want that?</div>
- <div class="tui-bottom">
- <div class="cc-rule"></div>
- <div><b>›</b> <span class="cursor"></span></div>
- <br />
- <div class="dim">gpt-5.5 medium · ~/data-pipeline · backfill/events-v2 · Context 6% used</div>
- </div>
- </div>
- </div>
- <div class="mock-panes single" data-tab="server">
- <div class="mock-pane focused">
- <div class="mock-prompt"><span>~/data-pipeline</span> <em>backfill/events-v2</em></div>
- <div><b>❯</b> <span class="cmd">uv</span> run jobs/backfill_events.py --from 2024-01-01</div>
- <div class="dim">connected · batch size 5,000 · checkpoint every 60s</div>
- <div><span class="time">02:28:41</span> batch 4,102 <span class="green">ok</span> <span class="dim">20,510,000 rows</span></div>
- <div><span class="time">02:29:03</span> batch 4,103 <span class="green">ok</span> <span class="dim">checkpoint written</span></div>
- <div><span class="time">02:29:25</span> batch 4,104 <span class="green">ok</span></div>
- <div><span class="time">02:30:07</span> batch 4,105 <span class="green">ok</span></div>
- <div><span class="time">02:30:18</span> <span class="red">WARN</span> upstream throttled, retrying in 2s</div>
- <div><span class="time">02:30:42</span> batch 4,106 <span class="green">ok</span> <span class="dim">checkpoint written</span></div>
- <div><span class="time">02:31:09</span> <span class="dim">elapsed 6h 12m · 68% complete · eta 2h 54m</span></div>
- </div>
- </div>
- </div>
- </section>
- </div>
- <figcaption>
- The whole herd in one terminal. Click the sidebar, it's a real layout.
- </figcaption>
- </figure>
- </div>
- <p class="figcap">A real session: three workspaces, four agents, two of them mid-task. <b>Nobody is attached to any of it right now</b> — that's the point. Click an agent in the sidebar, it's a live layout, not an image.</p>
- </section>
-
- <div class="caps">
- <a class="cap" href="/docs/session-state/">
- <div class="n"><span>01</span></div>
- <div class="cap-in">
- <h3>Always running.&nbsp;<b class="arw">&#8594;</b></h3>
- <p>Herdr isn't an app you keep open. It's a server running in the background, and the terminals live inside it. Close the lid or drop the network and the agents keep working; restart the machine and Herdr brings the layout back and resumes their sessions.</p>
- </div>
- <div class="ev" aria-hidden="true">
- <div class="ev-row"><span>herdr-server</span><b><i class="beat"></i>up</b></div>
- <div class="ev-note">3 workspaces &middot; 4 agents &middot; nobody attached</div>
- </div>
- </a>
- <a class="cap" href="/docs/agents/">
- <div class="n"><span>02</span></div>
- <div class="cap-in">
- <h3>You never hunt for the stuck one.&nbsp;<b class="arw">&#8594;</b></h3>
- <p>Herdr reads every pane and marks each agent working, blocked or idle. When one stops and needs an answer it says so, so you don't go pane by pane looking for whoever is waiting on you.</p>
- </div>
- <div class="ev" aria-hidden="true">
- <div class="ev-row"><span>web-dashboard</span><b><i class="b"></i>blocked</b></div>
- <div class="ev-row"><span>herdr</span><b><i class="w"></i>working</b></div>
- <div class="ev-row"><span>data-pipeline</span><b><i class="i"></i>idle</b></div>
- </div>
- </a>
- <a class="cap" href="/docs/agent-automation/">
- <div class="n"><span>03</span></div>
- <div class="cap-in">
- <h3>Agent-native.&nbsp;<b class="arw">&#8594;</b></h3>
- <p>The CLI and the socket API are the same surface agents drive. They split panes, start each other, prompt each other, and wait until another agent is genuinely blocked instead of firing keystrokes and hoping.</p>
- </div>
- <div class="ev">
- <div class="tape" aria-hidden="true"><b>$</b><span data-tape></span></div>
- </div>
- </a>
- <a class="cap" href="/docs/integrations/">
- <div class="n"><span>04</span></div>
- <div class="cap-in">
- <h3>Runs what you already run.&nbsp;<b class="arw">&#8594;</b></h3>
- <p>Claude Code, Codex, Cursor, opencode, Grok and the rest. Herdr doesn't wrap them or replace them, it just owns their terminals — one binary for macOS, Linux, and Windows.</p>
- </div>
- <div class="ev">
- <div class="herd">
- <span><i style="--m: url('/assets/agent-icons/claude.svg')"></i>Claude Code</span>
- <span><i style="--m: url('/assets/agent-icons/codex-mask.svg')"></i>Codex</span>
- <span><i style="--m: url('/assets/agent-icons/pi.svg')"></i>Pi</span>
- <span><i style="--m: url('/assets/agent-icons/opencode.svg')"></i>opencode</span>
- <span><i style="--m: url('/assets/agent-icons/cursor.svg')"></i>Cursor</span>
- <span><i style="--m: url('/assets/agent-icons/grok.svg')"></i>Grok</span>
- <span><i style="--m: url('/assets/agent-icons/github-copilot.svg')"></i>Copilot</span>
- <span><i style="--m: url('/assets/agent-icons/hermes.svg')"></i>Hermes</span>
- </div>
- <div class="ev-note"><!--AGENTS_NOTE--></div>
- </div>
- </a>
- <a class="cap cap-soon" href="/blog/herdr-is-joining-y-combinator/#where-were-going">
- <div class="n"><span>05</span><span class="soon-tag">soon</span></div>
- <div class="cap-in">
- <h3>Where do agents run while you sleep?&nbsp;<b class="arw">&#8594;</b></h3>
- <p aria-hidden="true"><span class="mask">████ █████████ █████████ ████ █ ████████ ████ ███ ██ ██ ██████ ███ ███ ██████ █████ █████ █████</span></p>
- <p class="sr">The answer is redacted for now. Read where Herdr is going in the Y Combinator announcement.</p>
- </div>
- <div class="ev">
- <div class="tape" aria-hidden="true"><b>$</b><span class="mask">█████ █████ █████</span></div>
- <div class="ev-note" aria-hidden="true"><span class="mask">███████ ███ █████ █████</span></div>
- </div>
- </a>
- </div>
-
- <section class="end" id="install">
- <span class="ram"></span>
- <div class="in">
- <h2>Give them somewhere to live.</h2>
- <p>One command, and nothing else about your setup changes — the agent CLIs you already run keep working exactly as they did, except now they don't stop when you do.</p>
- <div class="go">
- <div class="hd-cmd">
- <code id="install-cmd-2"><b>$</b>curl -fsSL https://herdr.dev/install.sh | sh</code>
- <button type="button" id="copy-btn-2" aria-label="Copy install command">copy</button>
- </div>
- </div>
- <div class="meta">Windows: <code>irm https://herdr.dev/install.ps1 | iex</code> &nbsp;—&nbsp; <a href="/docs/windows-beta/">endpoint-protected install</a> · <a href="/docs/">all install methods →</a></div>
- </div>
- </section>
-
- <footer class="foot">
- <span class="ram"></span>
- <a href="/docs/">docs</a>
- <a href="/plugins/">plugins</a>
- <a href="/blog/">blog</a>
- <a href="/compare/">compare</a>
- <span>built in the terminal · © 2026 Herdr, Inc.</span>
- <span class="fact"><!--FACTS--></span>
- <span class="out">
- <a class="ico" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub">
- <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" /></svg>
- </a>
- <a class="ico" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" /></svg>
- </a>
- <a href="mailto:hey@herdr.dev">hey@herdr.dev</a>
- </span>
- </footer>
-
- </div>
-
- <script>
- /* ground toggle — writes through to the key the docs read */
- (function () {
- var buttons = document.querySelectorAll("[data-ground]");
- function paint(mode) {
- window.herdrGround.apply(mode);
- buttons.forEach(function (b) {
- b.setAttribute("aria-pressed", String(b.dataset.ground === mode));
- });
- }
- buttons.forEach(function (b) {
- b.addEventListener("click", function () {
- window.herdrGround.save(b.dataset.ground);
- paint(b.dataset.ground);
- });
- });
- paint(window.herdrGround.read());
- })();
-
- /* nav sheet — the links, the account and the ground toggle that don't
- fit the bar on a phone */
- (function () {
- var btn = document.getElementById("nav-menu");
- var sheet = document.getElementById("nav-sheet");
- if (!btn || !sheet) return;
- function set(open) {
- sheet.classList.toggle("open", open);
- btn.setAttribute("aria-expanded", String(open));
- }
- btn.addEventListener("click", function (event) {
- event.stopPropagation();
- set(!sheet.classList.contains("open"));
- });
- /* the ground buttons live in the sheet, so a tap inside must not
- close it — only taps on the page behind do */
- document.addEventListener("click", function (event) {
- if (!sheet.contains(event.target)) set(false);
- });
- document.addEventListener("keydown", function (event) {
- if (event.key === "Escape") set(false);
- });
- })();
-
- /* The typing line in row 03. The commands are real and in workflow
- order — split a pane, start a reviewer, prompt it, wait until it is
- actually blocked, read what it said — so the animation is a demo
- rather than decoration. Runs only while the row is on screen, and
- reduced-motion gets the first line held still. */
- (function () {
- var out = document.querySelector("[data-tape]");
- if (!out) return;
-
- var LINES = [
- "herdr pane split --current --direction right --no-focus",
- "herdr agent start reviewer --kind codex",
- 'herdr agent prompt reviewer "Review the current diff" --wait',
- "herdr agent wait reviewer --until blocked",
- "herdr agent read reviewer --source recent-unwrapped",
- 'herdr pane wait-output w1:p3 --regex "passed|failed"',
- ];
-
- if (matchMedia("(prefers-reduced-motion: reduce)").matches) {
- out.textContent = LINES[0];
- return;
- }
-
- var line = 0, ch = 0, erasing = false, live = false, timer = null;
-
- function tick() {
- var text = LINES[line];
- if (!erasing) {
- ch++;
- out.textContent = text.slice(0, ch);
- if (ch >= text.length) {
- erasing = true;
- return schedule(1900);
- }
- return schedule(26 + Math.random() * 44);
- }
- ch -= 3;
- if (ch <= 0) {
- ch = 0;
- erasing = false;
- line = (line + 1) % LINES.length;
- out.textContent = "";
- return schedule(360);
- }
- out.textContent = text.slice(0, ch);
- return schedule(14);
- }
-
- function schedule(ms) {
- timer = setTimeout(function () {
- if (live) tick();
- }, ms);
- }
-
- /* no point animating a row nobody is looking at */
- new IntersectionObserver(function (entries) {
- entries.forEach(function (e) {
- if (e.isIntersecting && !live) {
- live = true;
- tick();
- } else if (!e.isIntersecting && live) {
- live = false;
- clearTimeout(timer);
- }
- });
- }, { threshold: 0.35 }).observe(out.closest(".tape"));
- })();
-
- /* copy buttons */
- (function () {
- [["copy-btn", "install-cmd"], ["copy-btn-2", "install-cmd-2"]].forEach(function (pair) {
- var button = document.getElementById(pair[0]);
- var source = document.getElementById(pair[1]);
- if (!button || !source) return;
- button.addEventListener("click", function () {
- var text = source.textContent.replace(/^\s*\$\s*/, "").trim();
- if (!text) return;
- navigator.clipboard.writeText(text).then(function () {
- var was = button.textContent;
- button.textContent = "copied";
- setTimeout(function () { button.textContent = was; }, 1400);
- }).catch(function () {});
- });
- });
- })();
-
- /* braille spinner in the mock */
- (function () {
- var frames = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
- var tick = 0;
- setInterval(function () {
- tick = (tick + 1) % frames.length;
- var els = document.querySelectorAll(".braille-spinner");
- for (var i = 0; i < els.length; i++) els[i].textContent = frames[tick];
- }, 80);
- })();
-
- /* the strip is already correct when it ships — baked at build from the
- same snapshots /stats/ and /plugins/ read. This refreshes it live and
- counts up to the new value if it moved since the last deploy. */
- (function () {
- var fmt = function (n) { return n.toLocaleString("en-US"); };
- var reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;
-
- function settle(el, target) {
- if (!el || typeof target !== "number") return;
- var from = Number(String(el.textContent).replace(/[^0-9]/g, "")) || 0;
- if (reduced || !from || from === target) { el.textContent = fmt(target); return; }
- var started = null, span = target - from;
- requestAnimationFrame(function step(now) {
- if (started === null) started = now;
- var t = Math.min(1, (now - started) / 900);
- var eased = 1 - Math.pow(1 - t, 3);
- el.textContent = fmt(Math.round(from + span * eased));
- if (t < 1) requestAnimationFrame(step);
- });
- }
-
- fetch("https://assets.herdr.dev/stats/stats.json", { headers: { accept: "application/json" } })
- .then(function (r) { return r.ok ? r.json() : null; })
- .then(function (d) {
- if (!d) return;
- if (d.stars) {
- settle(document.getElementById("n-stars"), d.stars.total);
- document.querySelectorAll("[data-stars]").forEach(function (el) {
- settle(el, d.stars.total);
- });
- }
- if (d.downloads) {
- settle(
- document.getElementById("n-installs"),
- (d.downloads.github || 0) + (d.downloads.brew || 0)
- );
- }
- })
- .catch(function () {});
-
- fetch("https://assets.herdr.dev/plugins/index.json", { headers: { accept: "application/json" } })
- .then(function (r) { return r.ok ? r.json() : null; })
- .then(function (d) {
- if (!d) return;
- /* pluginCount is validated manifests, which is what /plugins/
- lists. source.totalCount is the raw GitHub topic search and
- still counts blacklisted and manifest-less repositories, so
- reading it here made the homepage disagree with the page it
- links to. */
- var total = d.pluginCount || (d.plugins && d.plugins.length);
- if (total) settle(document.getElementById("n-plugins"), total);
- })
- .catch(function () {});
- })();
-
-/* herd mock: clickable workspaces, tabs, and agents */
- (function () {
- var mock = document.getElementById("herd-mock");
- if (!mock) return;
-
- function syncAgents() {
- var view = mock.querySelector(".mock-view.active");
- var tab = view && view.querySelector(".mock-tabs span.active");
- var ws = view && view.getAttribute("data-view");
- var tabId = tab && tab.getAttribute("data-tab");
- mock.querySelectorAll(".mock-agent").forEach(function (a) {
- a.classList.toggle(
- "active",
- a.getAttribute("data-ws-link") === ws &&
- a.getAttribute("data-tab-link") === tabId
- );
- });
- }
-
- function selectTab(tab) {
- var target = tab.getAttribute("data-tab");
- if (!target) return;
- tab.parentElement.querySelectorAll("span").forEach(function (t) {
- t.classList.remove("active");
- });
- tab.classList.add("active");
- var view = tab.closest(".mock-view");
- view.querySelectorAll(".mock-panes").forEach(function (panes) {
- panes.classList.toggle("active", panes.getAttribute("data-tab") === target);
- });
- syncAgents();
- }
-
- function activateWorkspace(id, tabId) {
- mock.querySelectorAll(".mock-space").forEach(function (ws) {
- ws.classList.toggle("active", ws.getAttribute("data-ws") === id);
- });
- mock.querySelectorAll(".mock-view").forEach(function (view) {
- view.classList.toggle("active", view.getAttribute("data-view") === id);
- });
- if (tabId) {
- var view = mock.querySelector('.mock-view[data-view="' + id + '"]');
- var tab = view && view.querySelector('.mock-tabs span[data-tab="' + tabId + '"]');
- if (tab) selectTab(tab);
- }
- syncAgents();
- }
-
- mock.querySelectorAll(".mock-space").forEach(function (ws) {
- ws.addEventListener("click", function () {
- activateWorkspace(ws.getAttribute("data-ws"));
- });
- });
-
- mock.querySelectorAll(".mock-agent").forEach(function (a) {
- a.addEventListener("click", function () {
- activateWorkspace(
- a.getAttribute("data-ws-link"),
- a.getAttribute("data-tab-link")
- );
- });
- });
-
- mock.querySelectorAll(".mock-tabs span").forEach(function (tab) {
- if (!tab.getAttribute("data-tab")) return;
- tab.addEventListener("click", function (event) {
- event.stopPropagation();
- selectTab(tab);
- });
- });
-
- /* the working counter keeps counting, like the real thing */
- var timer = document.getElementById("cc-timer");
- if (timer) {
- var seconds = 13 * 60 + 36;
- setInterval(function () {
- if (document.hidden) return;
- seconds += 1;
- if (seconds >= 16 * 60) seconds = 0; /* new turn, counter resets */
- timer.textContent = Math.floor(seconds / 60) + "m " + (seconds % 60) + "s";
- }, 1000);
- }
-
- })();
-
- </script>
- </body>
-</html>
diff --git a/website/package.json b/website/package.json
deleted file mode 100644
index d4474007..00000000
--- a/website/package.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "herdr-website",
- "private": true,
- "type": "module",
- "scripts": {
- "prepare-docs": "node scripts/prepare-docs.mjs",
- "prepare-llms": "node scripts/patch-starlight-llms.mjs",
- "dev": "bun run prepare-llms && node scripts/prepare-docs.mjs --draft && astro dev",
- "test": "bun test",
- "build": "bun run test && bun run prepare-llms && node scripts/prepare-docs.mjs && astro build && node scripts/check-built-docs.mjs",
- "build:draft": "bun run prepare-llms && node scripts/prepare-docs.mjs --draft && astro build && node scripts/check-built-docs.mjs",
- "preview": "astro preview"
- },
- "dependencies": {
- "@astrojs/sitemap": "^3.7.2",
- "@astrojs/starlight": "^0.36.0",
- "astro": "^5.0.0",
- "starlight-llms-txt": "0.6.1"
- }
-}
diff --git a/website/robots.txt b/website/robots.txt
deleted file mode 100644
index 2dccbcb9..00000000
--- a/website/robots.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-User-agent: *
-Allow: /
-
-Sitemap: https://herdr.dev/sitemap-index.xml
diff --git a/website/scripts/check-built-docs.mjs b/website/scripts/check-built-docs.mjs
deleted file mode 100644
index f6a2f199..00000000
--- a/website/scripts/check-built-docs.mjs
+++ /dev/null
@@ -1,178 +0,0 @@
-import { access, readFile, readdir, stat } from 'node:fs/promises';
-import { dirname, join, resolve } from 'node:path';
-import { fileURLToPath } from 'node:url';
-
-const websiteDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
-const distDir = resolve(websiteDir, 'dist');
-const nonCanonicalDocsUrl = /https:\/\/herdr\.dev\/(?:ja\/|zh-cn\/)?docs\/(?:preview|\d+\.\d+\.\d+)(?:\/|<)/;
-const versions = JSON.parse(
- await readFile(resolve(websiteDir, 'src/data/docs-versions.json'), 'utf8'),
-);
-
-for (const entry of versions.versions) {
- const scope = versions.scopes[entry.version];
- if (!scope) throw new Error(`missing generated scope for ${entry.version}`);
- for (const [locale, pages] of Object.entries(scope.locales)) {
- const localePrefix = locale === 'root' ? '' : `${locale}/`;
- for (const page of pages) {
- const output = resolve(
- distDir,
- localePrefix,
- 'docs',
- entry.version,
- page,
- 'index.html',
- );
- await access(output);
- }
- }
-}
-
-const stable = await readFile(resolve(distDir, 'docs/index.html'), 'utf8');
-const preview = await readFile(resolve(distDir, 'docs/preview/index.html'), 'utf8');
-const archived = await readFile(
- resolve(distDir, 'docs', versions.current, 'index.html'),
- 'utf8',
-);
-
-assertIncludes(stable, 'data-pagefind-filter="version[content]" content="stable"');
-if (stable.includes('name="robots" content="noindex')) {
- throw new Error('stable docs must remain indexable');
-}
-assertIncludes(preview, 'data-pagefind-filter="version[content]" content="preview"');
-assertIncludes(preview, `Preview build <code dir="auto">${versions.preview.build_id}</code>`);
-if (versions.preview.commit !== 'master') {
- assertIncludes(preview, versions.preview.commit.slice(0, 12));
-}
-assertIncludes(preview, 'name="robots" content="noindex, nofollow"');
-assertIncludes(archived, `data-pagefind-filter="version[content]" content="${versions.current}"`);
-assertIncludes(archived, 'name="robots" content="noindex, nofollow"');
-if (archived.includes(`This page documents Herdr ${versions.current}`)) {
- throw new Error('the current documentation version must not be labeled as outdated');
-}
-const versionSelect = stable.match(/<select[^>]*aria-label="Documentation version"[^>]*>([\s\S]*?)<\/select>/)?.[1];
-if (!versionSelect) throw new Error('stable docs are missing the version selector');
-if (versionSelect.includes(`value="/docs/${versions.current}/"`)) {
- throw new Error('the current release is duplicated in the version selector');
-}
-
-const previous = versions.versions.find((entry) => entry.version !== versions.current);
-if (previous) {
- const previousArchive = await readFile(
- resolve(distDir, 'docs', previous.version, 'index.html'),
- 'utf8',
- );
- assertIncludes(previousArchive, `This page documents Herdr ${previous.version}`);
-}
-
-const sitemap = await readFile(resolve(distDir, 'sitemap-0.xml'), 'utf8');
-assertIncludes(sitemap, 'https://herdr.dev/docs/');
-if (nonCanonicalDocsUrl.test(sitemap)) {
- throw new Error('preview or versioned documentation URLs must not appear in the sitemap');
-}
-
-const llmsIndex = await readFile(resolve(distDir, 'llms.txt'), 'utf8');
-const llmsPreview = await readFile(resolve(distDir, 'llms-preview.txt'), 'utf8');
-const llmsSmall = await readFile(resolve(distDir, 'llms-small.txt'), 'utf8');
-const llmsFull = await readFile(resolve(distDir, 'llms-full.txt'), 'utf8');
-const headers = await readFile(resolve(distDir, '_headers'), 'utf8');
-const currentDocs = versions.versions.find((entry) => entry.version === versions.current);
-if (!currentDocs?.tag || !currentDocs.source) {
- throw new Error(`current docs version ${versions.current} is missing its tag or source`);
-}
-const stableRawRoot = `https://raw.githubusercontent.com/herdrdev/herdr/${currentDocs.tag}`;
-const stableRawBase = `${stableRawRoot}/${currentDocs.source}`;
-const stableConfigReferenceUrl = `${stableRawRoot}/${currentDocs.source.replace(/\/content\/docs$/, '/data/config-reference.json')}`;
-const previewRawRoot = `https://raw.githubusercontent.com/herdrdev/herdr/${versions.preview.commit}`;
-const previewRawBase = `${previewRawRoot}/docs/next/website/src/content/docs`;
-const previewConfigReferenceUrl = `${previewRawRoot}/docs/next/website/src/data/config-reference.json`;
-assertIncludes(llmsIndex, `Current stable release: ${versions.current}.`);
-assertIncludes(llmsIndex, `${stableRawBase}/quick-start.mdx`);
-assertIncludes(llmsIndex, `- [Config reference](${stableConfigReferenceUrl})`);
-assertIncludes(llmsIndex, '## Using the config reference');
-assertIncludes(llmsIndex, "jq --arg key 'ui.sidebar_width'");
-if (llmsIndex.includes(`${stableRawBase}/config-reference.mdx`)) {
- throw new Error('llms.txt must link to config reference data instead of the unrendered MDX component');
-}
-assertIncludes(llmsIndex, 'https://herdr.dev/llms-small.txt');
-assertIncludes(llmsIndex, 'https://herdr.dev/llms-full.txt');
-assertIncludes(llmsIndex, 'https://herdr.dev/agent-guide.md');
-assertIncludes(llmsIndex, 'https://herdr.dev/llms-preview.txt');
-assertIncludes(llmsPreview, `Active preview build: ${versions.preview.build_id}`);
-assertIncludes(llmsPreview, `${previewRawBase}/quick-start.mdx`);
-assertIncludes(llmsPreview, `- [Config reference](${previewConfigReferenceUrl})`);
-if (llmsPreview.includes(`${previewRawBase}/config-reference.mdx`)) {
- throw new Error('llms-preview.txt must link to config reference data instead of the unrendered MDX component');
-}
-assertIncludes(llmsPreview, 'https://herdr.dev/llms.txt');
-const stablePageLinks = llmsIndex
- .split('\n')
- .filter(
- (line) =>
- line.includes(`](${stableRawBase}/`) || line.includes(`](${stableConfigReferenceUrl})`),
- );
-if (stablePageLinks.length !== versions.scopes.stable.locales.root.length) {
- throw new Error(
- `llms.txt lists ${stablePageLinks.length} stable pages, expected ${versions.scopes.stable.locales.root.length}`,
- );
-}
-const previewPageLinks = llmsPreview
- .split('\n')
- .filter(
- (line) =>
- line.includes(`](${previewRawBase}/`) || line.includes(`](${previewConfigReferenceUrl})`),
- );
-if (previewPageLinks.length !== versions.scopes.preview.locales.root.length) {
- throw new Error(
- `llms-preview.txt lists ${previewPageLinks.length} preview pages, expected ${versions.scopes.preview.locales.root.length}`,
- );
-}
-for (const path of ['/llms.txt', '/llms-preview.txt', '/llms-small.txt', '/llms-full.txt']) {
- assertIncludes(headers, `${path}\n Content-Type: text/markdown; charset=utf-8`);
-}
-for (const [name, content] of [
- ['llms-small.txt', llmsSmall],
- ['llms-full.txt', llmsFull],
-]) {
- assertIncludes(content, '# Herdr documentation');
- assertIncludes(content, '# Troubleshooting');
- assertIncludes(content, '# Socket API');
- if (content.match(/^# Herdr documentation$/gm)?.length !== 1) {
- throw new Error(`${name} must contain exactly one stable documentation set`);
- }
- if (/\]\(\/docs\/(?:preview|\d+\.\d+\.\d+)(?:\/|\))/.test(content)) {
- throw new Error(`${name} must not link to preview or versioned documentation`);
- }
-}
-
-const build = await inspectFiles(distDir);
-if (build.count > 20_000) {
- throw new Error(`website build has ${build.count} files, exceeding the Cloudflare Pages free-plan limit`);
-}
-if (build.largest.bytes > 25 * 1024 * 1024) {
- throw new Error(`website asset ${build.largest.path} is ${build.largest.bytes} bytes, exceeding Cloudflare Pages' 25 MiB limit`);
-}
-process.stdout.write(`validated ${versions.versions.length} documentation versions in ${build.count} website files\n`);
-
-function assertIncludes(content, expected) {
- if (!content.includes(expected)) throw new Error(`built documentation is missing ${expected}`);
-}
-
-async function inspectFiles(directory, root = directory) {
- const result = { count: 0, largest: { path: '', bytes: 0 } };
- for (const entry of await readdir(directory, { withFileTypes: true })) {
- const path = join(directory, entry.name);
- if (entry.isDirectory()) {
- const nested = await inspectFiles(path, root);
- result.count += nested.count;
- if (nested.largest.bytes > result.largest.bytes) result.largest = nested.largest;
- } else if (entry.isFile()) {
- result.count += 1;
- const { size } = await stat(path);
- if (size > result.largest.bytes) {
- result.largest = { path: path.slice(root.length + 1), bytes: size };
- }
- }
- }
- return result;
-}
diff --git a/website/scripts/patch-starlight-llms.mjs b/website/scripts/patch-starlight-llms.mjs
deleted file mode 100644
index 3582b6f6..00000000
--- a/website/scripts/patch-starlight-llms.mjs
+++ /dev/null
@@ -1,54 +0,0 @@
-import { readFile, writeFile } from 'node:fs/promises';
-import { resolve } from 'node:path';
-
-await patchFullBundleExclusions();
-await disablePluginIndexRoute();
-
-async function patchFullBundleExclusions() {
- const path = resolve('node_modules/starlight-llms-txt/llms-full.txt.ts');
- const original = await readFile(path, 'utf8');
- const importLine =
- "import { starlightLllmsTxtContext } from 'virtual:starlight-llms-txt/context';";
- const excludeLine = '\t\texclude: starlightLllmsTxtContext.exclude,';
-
- if (original.includes(importLine) && original.includes(excludeLine)) return;
-
- const withImport = original.replace(
- "import { generateLlmsTxt } from './generator';",
- `${importLine}\nimport { generateLlmsTxt } from './generator';`,
- );
- const patched = withImport.replace(
- '\t\tdescription: `This is the full developer documentation for ${getSiteTitle()}`,',
- '\t\tdescription: `This is the full developer documentation for ${getSiteTitle()}`,\n' +
- excludeLine,
- );
-
- if (patched === original || !patched.includes(importLine) || !patched.includes(excludeLine)) {
- throw new Error(
- 'starlight-llms-txt changed: update the stable-only llms-full compatibility patch',
- );
- }
-
- await writeFile(path, patched, 'utf8');
-}
-
-async function disablePluginIndexRoute() {
- const path = resolve('node_modules/starlight-llms-txt/index.ts');
- const original = await readFile(path, 'utf8');
- const marker =
- '\t\t\t\t\t\t\t// Herdr publishes channel-aware raw-source indexes from website/public.';
- if (original.includes(marker)) return;
-
- const route = `\t\t\t\t\t\t\tinjectRoute({
-\t\t\t\t\t\t\t\tentrypoint: new URL('./llms.txt.ts', import.meta.url),
-\t\t\t\t\t\t\t\tpattern: '/llms.txt',
-\t\t\t\t\t\t\t});`;
- const patched = original.replace(route, marker);
- if (patched === original || !patched.includes(marker)) {
- throw new Error(
- 'starlight-llms-txt changed: update the custom llms.txt index compatibility patch',
- );
- }
-
- await writeFile(path, patched, 'utf8');
-}
diff --git a/website/scripts/prepare-docs.mjs b/website/scripts/prepare-docs.mjs
deleted file mode 100644
index 1fc8bc56..00000000
--- a/website/scripts/prepare-docs.mjs
+++ /dev/null
@@ -1,479 +0,0 @@
-import { cp, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
-import { dirname, extname, join, relative, resolve } from 'node:path';
-import { fileURLToPath } from 'node:url';
-import process from 'node:process';
-
-const websiteDir = dirname(fileURLToPath(import.meta.url));
-const repoRoot = process.env.HERDR_DOCS_REPO_ROOT
- ? resolve(process.env.HERDR_DOCS_REPO_ROOT)
- : resolve(websiteDir, '../..');
-const publicDir = resolve(repoRoot, 'website/public');
-const stableDocsDir = resolve(repoRoot, 'website/src/content/docs');
-const previewDocsDir = resolve(stableDocsDir, 'preview');
-const generatedVersionsDocsDir = resolve(stableDocsDir, '_versions');
-const versionsDir = resolve(repoRoot, 'docs/versions');
-const versionsManifestPath = resolve(versionsDir, 'manifest.json');
-const previewManifestPath = resolve(repoRoot, 'website/preview.json');
-const generatedVersionsDataPath = resolve(repoRoot, 'website/src/data/docs-versions.json');
-const stableConfigReferenceDestination = resolve(
- repoRoot,
- 'website/src/data/config-reference.json',
-);
-const previewConfigReferenceDestination = resolve(
- repoRoot,
- 'website/src/data/config-reference-preview.json',
-);
-const generatedVersionReferencesPath = resolve(
- repoRoot,
- 'website/src/data/config-reference-versions.json',
-);
-
-if (process.argv[2] === '--rewrite-preview-doc-fixture') {
- const chunks = [];
- for await (const chunk of process.stdin) chunks.push(chunk);
- process.stdout.write(
- rewritePreviewDocContent(Buffer.concat(chunks).toString('utf8'), '', {
- buildId: '2026-07-29-44b3adb12552',
- commit: '44b3adb125524ea9a55739eee3776f922f2115ad',
- }),
- );
-} else if (process.argv[2] === '--rewrite-version-doc-fixture') {
- const chunks = [];
- for await (const chunk of process.stdin) chunks.push(chunk);
- process.stdout.write(
- rewriteVersionDocContent(Buffer.concat(chunks).toString('utf8'), {
- version: process.argv[3] ?? '0.7.5',
- tag: `v${process.argv[3] ?? '0.7.5'}`,
- relativePath: 'index.mdx',
- }),
- );
-} else {
- const supported = new Set(['--docs-only', '--draft']);
- const unsupported = process.argv.slice(2).filter((argument) => !supported.has(argument));
- if (unsupported.length > 0) {
- throw new Error('usage: node website/scripts/prepare-docs.mjs [--docs-only] [--draft]');
- }
- const docsOnly = process.argv.includes('--docs-only');
- if (!docsOnly) await preparePublicAssets();
- await prepareDocs({
- draft: process.argv.includes('--draft'),
- publishAgentIndexes: !docsOnly,
- });
-}
-
-async function preparePublicAssets() {
- await rm(publicDir, { recursive: true, force: true });
- await mkdir(publicDir, { recursive: true });
-
- for (const file of [
- 'install.sh',
- 'install.ps1',
- 'install.cmd',
- 'agent-guide.md',
- 'latest.json',
- 'preview.json',
- 'robots.txt',
- 'favicon.ico',
- '_headers',
- '_redirects',
- ]) {
- const source = resolve(repoRoot, 'website', file);
- try {
- await cp(source, resolve(publicDir, file));
- } catch (error) {
- if (file !== 'preview.json' || error.code !== 'ENOENT') throw error;
- }
- }
-
- for (const directory of ['assets', 'css', 'agent-detection']) {
- await cp(resolve(repoRoot, 'website', directory), resolve(publicDir, directory), {
- recursive: true,
- });
- }
-}
-
-async function prepareDocs({ draft, publishAgentIndexes }) {
- const manifest = JSON.parse(await readFile(versionsManifestPath, 'utf8'));
- if (
- manifest.schema_version !== 1 ||
- typeof manifest.current !== 'string' ||
- !['legacy', 'snapshot'].includes(manifest.stable_source ?? 'legacy')
- ) {
- throw new Error(`${versionsManifestPath} has an unsupported schema`);
- }
- const currentEntry = manifest.versions.find((entry) => entry.version === manifest.current);
- if (!currentEntry) throw new Error(`current docs version ${manifest.current} has no snapshot`);
-
- const previewManifest = JSON.parse(await readFile(previewManifestPath, 'utf8'));
- if (!/^[0-9a-f]{40}$/.test(previewManifest.commit ?? '')) {
- throw new Error(`${previewManifestPath} must contain a full preview commit SHA`);
- }
- const previewWebsiteRoot = resolve(repoRoot, draft ? 'docs/next/website' : 'docs/preview/website');
- const previewDocsSourceDir = resolve(previewWebsiteRoot, 'src/content/docs');
- const previewConfigReferenceSource = resolve(
- previewWebsiteRoot,
- 'src/data/config-reference.json',
- );
-
- if ((manifest.stable_source ?? 'legacy') === 'snapshot') {
- await rm(stableDocsDir, { recursive: true, force: true });
- const currentSnapshotRoot = resolve(versionsDir, manifest.current, 'website');
- await copyPreparedDocs(
- resolve(currentSnapshotRoot, 'src/content/docs'),
- stableDocsDir,
- (content, relativePath) =>
- rewriteStableDocContent(content, {
- version: currentEntry.version,
- tag: currentEntry.tag,
- relativePath,
- }),
- );
- const currentReference = resolve(currentSnapshotRoot, 'src/data/config-reference.json');
- try {
- await cp(currentReference, stableConfigReferenceDestination);
- } catch (error) {
- if (error.code !== 'ENOENT') throw error;
- await rm(stableConfigReferenceDestination, { force: true });
- }
- } else {
- await rm(previewDocsDir, { recursive: true, force: true });
- await rm(generatedVersionsDocsDir, { recursive: true, force: true });
- }
-
- await copyPreparedDocs(previewDocsSourceDir, previewDocsDir, (content, relativePath) =>
- rewritePreviewDocContent(content, relativePath, {
- buildId: draft ? 'draft' : previewManifest.build_id,
- commit: draft ? 'master' : previewManifest.commit,
- }),
- );
- await cp(previewConfigReferenceSource, previewConfigReferenceDestination);
-
- const scopes = {
- stable: await collectDocsScope(
- (manifest.stable_source ?? 'legacy') === 'snapshot'
- ? resolve(versionsDir, manifest.current, 'website/src/content/docs')
- : stableDocsDir,
- new Set(['preview', '_versions']),
- ),
- preview: await collectDocsScope(previewDocsSourceDir),
- };
- const configReferences = {};
-
- for (const entry of manifest.versions) {
- const version = entry.version;
- const snapshotDocsRoot = resolve(versionsDir, version, 'website/src/content/docs');
- const destinationRoot = resolve(generatedVersionsDocsDir, version);
- await copyPreparedDocs(snapshotDocsRoot, destinationRoot, (content, relativePath) =>
- rewriteVersionDocContent(content, {
- version,
- tag: entry.tag,
- relativePath,
- }),
- );
- scopes[version] = await collectDocsScope(snapshotDocsRoot);
-
- const referencePath = resolve(
- versionsDir,
- version,
- 'website/src/data/config-reference.json',
- );
- try {
- configReferences[version] = JSON.parse(await readFile(referencePath, 'utf8'));
- } catch (error) {
- if (error.code !== 'ENOENT') throw error;
- }
- }
-
- await writeFile(
- generatedVersionsDataPath,
- `${JSON.stringify({
- ...manifest,
- preview: {
- build_id: draft ? 'draft' : previewManifest.build_id,
- commit: draft ? 'master' : previewManifest.commit,
- },
- scopes,
- }, null, 2)}\n`,
- 'utf8',
- );
- await writeFile(
- generatedVersionReferencesPath,
- `${JSON.stringify(configReferences, null, 2)}\n`,
- 'utf8',
- );
-
- if (publishAgentIndexes) {
- if (typeof currentEntry.tag !== 'string' || typeof currentEntry.source !== 'string') {
- throw new Error(`current docs version ${manifest.current} is missing its tag or source`);
- }
- const stableSourceDir = resolve(versionsDir, manifest.current, 'website/src/content/docs');
- const previewRef = draft ? 'master' : previewManifest.commit;
- const previewBuild = draft ? 'draft' : previewManifest.build_id;
- await Promise.all([
- writeAgentDocsIndex({
- output: resolve(publicDir, 'llms.txt'),
- heading: 'Herdr stable documentation index',
- summary: `Current stable release: ${manifest.current}.`,
- sourceDir: stableSourceDir,
- ref: currentEntry.tag,
- repositoryPath: currentEntry.source,
- extraSections: [
- '## Optional bundles',
- '- [Abridged documentation](https://herdr.dev/llms-small.txt)',
- '- [Complete documentation](https://herdr.dev/llms-full.txt)',
- '',
- '## Other resources',
- '- [Agent guide](https://herdr.dev/agent-guide.md): help a human understand, set up, or troubleshoot Herdr',
- '- [Preview documentation](https://herdr.dev/llms-preview.txt): use only for the preview channel',
- ],
- }),
- writeAgentDocsIndex({
- output: resolve(publicDir, 'llms-preview.txt'),
- heading: 'Herdr preview documentation index',
- summary: `Active preview build: ${previewBuild} (${previewRef.slice(0, 12)}).`,
- sourceDir: previewDocsSourceDir,
- ref: previewRef,
- repositoryPath: 'docs/next/website/src/content/docs',
- extraSections: [
- '## Other resources',
- '- [Stable documentation](https://herdr.dev/llms.txt): use unless the human is running the preview channel',
- '- [Agent guide](https://herdr.dev/agent-guide.md): help a human understand, set up, or troubleshoot Herdr',
- ],
- }),
- ]);
- }
-}
-
-async function writeAgentDocsIndex({
- output,
- heading,
- summary,
- sourceDir,
- ref,
- repositoryPath,
- extraSections,
-}) {
- const pages = await collectAgentDocs(sourceDir);
- const rawRoot = `https://raw.githubusercontent.com/herdrdev/herdr/${ref}`;
- const rawBase = `${rawRoot}/${repositoryPath}`;
- const configDataPath = repositoryPath.replace(
- /\/content\/docs$/,
- '/data/config-reference.json',
- );
- if (configDataPath === repositoryPath) {
- throw new Error(`cannot derive config reference path from ${repositoryPath}`);
- }
- const configDataUrl = `${rawRoot}/${configDataPath}`;
-
- const lines = [
- `# ${heading}`,
- '',
- `> ${summary}`,
- '',
- 'Open only the pages relevant to the current task. Links return raw source files from the exact documented revision. For another topic, return to this index instead of following `/docs/` links inside a page, which serve human-facing HTML.',
- '',
- '## Documentation',
- '',
- ...pages.map(({ title, description, path }) => {
- const url = /^config-reference\.mdx?$/.test(path) ? configDataUrl : `${rawBase}/${path}`;
- return `- [${title}](${url})${description ? `: ${description}` : ''}`;
- }),
- '',
- '## Using the config reference',
- '',
- 'The Config reference link above is a large structured JSON file. When command tools are available, fetch and filter it by exact key instead of loading the whole file:',
- '',
- '```sh',
- `curl -fsSL '${configDataUrl}' | jq --arg key 'ui.sidebar_width' \\`,
- " '.sections[].keys[] | select(.key == $key)'",
- '```',
- '',
- ...extraSections,
- '',
- ];
- await writeFile(output, lines.join('\n'), 'utf8');
-}
-
-async function collectAgentDocs(sourceDir) {
- const pages = [];
-
- async function walk(directory, prefix = '') {
- for (const entry of await readdir(directory, { withFileTypes: true })) {
- if (!prefix && entry.isDirectory() && ['ja', 'zh-cn'].includes(entry.name)) continue;
- const path = join(directory, entry.name);
- const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
- if (entry.isDirectory()) {
- await walk(path, relativePath);
- continue;
- }
- if (!entry.isFile() || !['.md', '.mdx'].includes(extname(entry.name).toLowerCase())) {
- continue;
- }
- const content = await readFile(path, 'utf8');
- const title = frontmatterValue(content, 'title');
- if (!title) throw new Error(`${path} is missing a frontmatter title`);
- pages.push({
- title,
- description: frontmatterValue(content, 'description'),
- path: relativePath,
- });
- }
- }
-
- await walk(sourceDir);
- pages.sort((a, b) => {
- if (a.path === 'index.mdx' || a.path === 'index.md') return -1;
- if (b.path === 'index.mdx' || b.path === 'index.md') return 1;
- return a.title.localeCompare(b.title, 'en');
- });
- return pages;
-}
-
-function frontmatterValue(content, key) {
- const frontmatter = content.match(/^---\n([\s\S]*?)\n---(?:\n|$)/)?.[1];
- const value = frontmatter?.match(new RegExp(`^${key}:\\s*(.+)$`, 'm'))?.[1]?.trim();
- if (!value) return undefined;
- const quote = value[0];
- return (quote === '"' || quote === "'") && value.endsWith(quote)
- ? value.slice(1, -1)
- : value;
-}
-
-async function copyPreparedDocs(sourceDir, destinationDir, rewrite, pathPrefix = '') {
- await mkdir(destinationDir, { recursive: true });
- for (const entry of await readdir(sourceDir, { withFileTypes: true })) {
- const source = join(sourceDir, entry.name);
- const destination = join(destinationDir, entry.name);
- const relativePath = pathPrefix ? `${pathPrefix}/${entry.name}` : entry.name;
- if (entry.isDirectory()) {
- await copyPreparedDocs(source, destination, rewrite, relativePath);
- continue;
- }
- if (!entry.isFile()) continue;
-
- if (!['.md', '.mdx'].includes(extname(entry.name).toLowerCase())) {
- await cp(source, destination);
- continue;
- }
- const content = await readFile(source, 'utf8');
- await writeFile(destination, rewrite(content, relativePath), 'utf8');
- }
-}
-
-async function collectDocsScope(sourceDir, excludedDirectories = new Set()) {
- const locales = { root: [], ja: [], 'zh-cn': [] };
-
- async function walk(directory, prefix = '') {
- for (const entry of await readdir(directory, { withFileTypes: true })) {
- if (entry.isDirectory() && excludedDirectories.has(entry.name)) continue;
- const path = join(directory, entry.name);
- const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
- if (entry.isDirectory()) {
- await walk(path, relativePath);
- continue;
- }
- if (!entry.isFile() || !['.md', '.mdx'].includes(extname(entry.name))) continue;
-
- const segments = relativePath.replace(/\.(md|mdx)$/i, '').split('/');
- const locale = segments[0] === 'ja' || segments[0] === 'zh-cn' ? segments.shift() : 'root';
- const page = segments.join('/').replace(/(^|\/)index$/, '').replace(/\/$/, '');
- locales[locale].push(page);
- }
- }
-
- await walk(sourceDir);
- for (const pages of Object.values(locales)) pages.sort();
- for (const locale of ['ja', 'zh-cn']) {
- if (locales[locale].length === 0) locales[locale] = [...locales.root];
- }
- return { locales };
-}
-
-export function rewritePreviewDocContent(
- content,
- relativePath = '',
- { buildId, commit } = {
- buildId: 'preview',
- commit: 'master',
- },
-) {
- const taggedContent = rewriteRepositoryLinks(
- content.replaceAll('/docs/', '/docs/preview/'),
- commit,
- );
- const rewritten = rewriteRelativeDocPaths(taggedContent, 1);
- const withSourceLink = setGeneratedEditUrl(
- rewritten,
- `https://github.com/herdrdev/herdr/blob/${commit}/docs/next/website/src/content/docs/${relativePath}`,
- );
- return insertPreviewNotice(withSourceLink, relativePath, { buildId, commit });
-}
-
-export function rewriteStableDocContent(content, { version, tag, relativePath }) {
- const taggedContent = rewriteRepositoryLinks(content, tag);
- return setGeneratedEditUrl(taggedContent, versionedDocSourceUrl(version, relativePath));
-}
-
-export function rewriteVersionDocContent(content, { version, tag, relativePath }) {
- const taggedContent = rewriteRepositoryLinks(
- content.replaceAll('/docs/', `/docs/${version}/`),
- tag,
- );
- const rewritten = rewriteRelativeDocPaths(taggedContent, 2);
- return setGeneratedEditUrl(rewritten, versionedDocSourceUrl(version, relativePath));
-}
-
-function versionedDocSourceUrl(version, relativePath) {
- return `https://github.com/herdrdev/herdr/blob/master/docs/versions/${version}/website/src/content/docs/${relativePath}`;
-}
-
-function rewriteRepositoryLinks(content, ref) {
- return content
- .replaceAll(
- 'https://github.com/herdrdev/herdr/blob/master/',
- `https://github.com/herdrdev/herdr/blob/${ref}/`,
- )
- .replaceAll(
- 'https://raw.githubusercontent.com/herdrdev/herdr/master/',
- `https://raw.githubusercontent.com/herdrdev/herdr/${ref}/`,
- );
-}
-
-function rewriteRelativeDocPaths(content, extraDepth) {
- const parents = '../'.repeat(extraDepth);
- return content
- .replace(/((?:\.\.\/)+)(?=public\/)/g, `$1${parents}`)
- .replace(/^(import .*from\s+['"])(?=(?:\.\.\/)+components\/)/gm, `$1${parents}`);
-}
-
-function setGeneratedEditUrl(content, editUrl) {
- if (!content.startsWith('---\n') || /^editUrl:/m.test(content)) return content;
- return content.replace(/^---\n/, `---\neditUrl: ${editUrl}\n`);
-}
-
-function insertPreviewNotice(content, relativePath, { buildId, commit }) {
- const source = commit === 'master' ? '`master` draft' : `[${commit.slice(0, 12)}](https://github.com/herdrdev/herdr/commit/${commit})`;
- const notice = [
- `> Preview build \`${buildId}\`, published from ${source}. Stable docs remain at [/docs/](/docs/).`,
- '',
- '',
- ].join('\n');
- const indexPrefix =
- relativePath === 'index.mdx'
- ? content.replace('title: Herdr documentation', 'title: Herdr preview documentation')
- : content;
- const frontmatter = indexPrefix.match(/^---\n[\s\S]*?\n---\n/);
- if (!frontmatter) {
- return insertNoticeAfterImports(indexPrefix, notice);
- }
- const body = indexPrefix.slice(frontmatter[0].length);
- return `${frontmatter[0]}\n${insertNoticeAfterImports(body, notice)}`;
-}
-
-function insertNoticeAfterImports(content, notice) {
- const imports = content.match(/^(\s*import .+?;\n)+\s*/);
- if (!imports) {
- return `${notice}${content}`;
- }
- return `${imports[0]}${notice}${content.slice(imports[0].length)}`;
-}
diff --git a/website/src/components/AuthorCard.astro b/website/src/components/AuthorCard.astro
deleted file mode 100644
index ba3a1014..00000000
--- a/website/src/components/AuthorCard.astro
+++ /dev/null
@@ -1,30 +0,0 @@
----
-const name = 'Can Celik';
-const role = 'Building Herdr';
-const photo = '/assets/author-can.jpeg';
-const x = 'https://x.com/cancelik';
-const email = 'can@herdr.dev';
----
-
-<aside class="author-card" aria-label="About the author">
- <img class="author-photo" src={photo} width="72" height="72" alt={name} loading="lazy" decoding="async" />
- <div class="author-body">
- <p class="author-name">{name}</p>
- <p class="author-role">{role}</p>
- <div class="author-links">
- <a href={x} target="_blank" rel="me noopener" aria-label={`${name} on X`}>
- <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="currentColor">
- <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
- </svg>
- <span>X</span>
- </a>
- <a href={`mailto:${email}`} aria-label={`Email ${name}`}>
- <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
- <rect x="2.5" y="4.5" width="19" height="15" rx="2" />
- <path d="m3 6 9 7 9-7" />
- </svg>
- <span>Email</span>
- </a>
- </div>
- </div>
-</aside>
diff --git a/website/src/components/Banner.astro b/website/src/components/Banner.astro
deleted file mode 100644
index cc6567a6..00000000
--- a/website/src/components/Banner.astro
+++ /dev/null
@@ -1,75 +0,0 @@
----
-import versions from '../data/docs-versions.json';
-import { docsRoute, docsTargetHref } from '../docs-path';
-
-const { entry, locale, isFallback } = Astro.locals.starlightRoute;
-const { banner } = entry.data;
-
-const issuesUrl = 'https://github.com/herdrdev/herdr/issues/new?template=translation.yml';
-const translationNotices = {
- ja: `このページの翻訳は LLM によって生成されています。誤りに気づいた場合は <a href="${issuesUrl}">GitHub で issue を開いて</a>お知らせください。`,
- 'zh-cn': `本页面的翻译由 LLM 生成。如果你发现翻译有误,请<a href="${issuesUrl}">在 GitHub 上提交 issue</a> 告诉我们。`,
-};
-const translationNotice = locale && !isFallback ? translationNotices[locale] : undefined;
-const docs = docsRoute(Astro.url.pathname);
-const archivedVersion =
- docs.target !== 'stable' && docs.target !== 'preview' && docs.target !== versions.current
- ? docs.target
- : undefined;
-const latestHref = docsTargetHref(docs, 'stable', versions.scopes);
-const archivedNotices = {
- root: `This page documents Herdr ${archivedVersion}. <a href="${latestHref}">Switch to the latest release.</a>`,
- ja: `このページは Herdr ${archivedVersion} のドキュメントです。<a href="${latestHref}">最新版に切り替えてください。</a>`,
- 'zh-cn': `本页面是 Herdr ${archivedVersion} 的文档。<a href="${latestHref}">切换到最新版本。</a>`,
-};
-const archivedNotice = archivedVersion ? archivedNotices[locale ?? 'root'] : undefined;
----
-
-{banner && <div class="sl-banner" data-pagefind-ignore set:html={banner.content} />}
-{archivedNotice && (
- <div class="version-notice" data-pagefind-ignore set:html={archivedNotice} />
-)}
-{translationNotice && (
- <div class="translation-notice" data-pagefind-ignore set:html={translationNotice} />
-)}
-
-<style>
- @layer starlight.core {
- .sl-banner {
- --__sl-banner-text: var(--sl-color-banner-text, var(--sl-color-text-invert));
- padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
- background-color: var(--sl-color-banner-bg, var(--sl-color-bg-accent));
- color: var(--__sl-banner-text);
- line-height: var(--sl-line-height-headings);
- text-align: center;
- text-wrap: balance;
- box-shadow: var(--sl-shadow-sm);
- }
- .sl-banner :global(a) {
- color: var(--__sl-banner-text);
- }
-
- .translation-notice,
- .version-notice {
- padding: 0.5rem var(--sl-nav-pad-x);
- background-color: var(--sl-color-bg-nav);
- border-bottom: 1px solid var(--sl-color-hairline);
- color: var(--sl-color-gray-2);
- font-size: var(--sl-text-xs);
- line-height: var(--sl-line-height-headings);
- text-align: center;
- text-wrap: balance;
- }
- .version-notice {
- background-color: var(--sl-color-orange-low);
- border-bottom-color: var(--sl-color-orange);
- color: var(--sl-color-orange-high);
- }
- .translation-notice :global(a) {
- color: var(--sl-color-text-accent);
- }
- .version-notice :global(a) {
- color: var(--sl-color-orange-high);
- }
- }
-</style>
diff --git a/website/src/components/ConfigReference.astro b/website/src/components/ConfigReference.astro
deleted file mode 100644
index 33894993..00000000
--- a/website/src/components/ConfigReference.astro
+++ /dev/null
@@ -1,204 +0,0 @@
----
-import stableReference from '../data/config-reference.json';
-import previewReference from '../data/config-reference-preview.json';
-import versionReferences from '../data/config-reference-versions.json';
-import { docsVersion } from '../docs-path';
-
-interface Props {
- placeholder?: string;
- noMatches?: string;
- keyCountLabel?: string;
-}
-
-const {
- placeholder = 'filter keys, e.g. sidebar, prefix, sound…',
- noMatches = 'No keys match this filter.',
- keyCountLabel = 'keys',
-} = Astro.props;
-
-const version = docsVersion(Astro.url.pathname);
-const archivedReferences = versionReferences as Record<string, typeof stableReference>;
-const reference = version === 'preview'
- ? previewReference
- : version === 'stable'
- ? stableReference
- : archivedReferences[version];
-if (!reference) {
- throw new Error(`documentation version ${version} has no archived configuration reference`);
-}
-const totalKeys = reference.sections.reduce((sum, section) => sum + section.keys.length, 0);
----
-
-<div class="config-reference" data-count-label={keyCountLabel}>
- <div class="config-reference-controls">
- <input
- type="search"
- class="config-reference-filter"
- placeholder={placeholder}
- autocomplete="off"
- spellcheck="false"
- aria-label={placeholder}
- />
- <p class="config-reference-meta" aria-live="polite">{totalKeys} {keyCountLabel}</p>
- </div>
-
- {reference.sections.map((section) => (
- <section class="config-reference-section">
- <h2 class="config-reference-title" id={`ref-${section.id}`}>{section.title}</h2>
- <ul class="config-reference-list">
- {section.keys.map((entry) => (
- <li
- class="config-reference-row"
- data-search={`${entry.key} ${entry.description} ${(entry.values ?? []).join(' ')}`.toLowerCase()}
- >
- <div class="config-reference-head">
- <code class="config-reference-key">{entry.key}</code>
- <span class="config-reference-type">{entry.type}</span>
- {entry.default && (
- <span class="config-reference-default">
- default <code>{entry.default}</code>
- </span>
- )}
- </div>
- <p class="config-reference-desc">
- {entry.description}
- {entry.values && (
- <span class="config-reference-values">
- {entry.values.map((value) => (
- <code>{value}</code>
- ))}
- </span>
- )}
- </p>
- </li>
- ))}
- </ul>
- </section>
- ))}
-
- <p class="config-reference-empty" hidden>{noMatches}</p>
-</div>
-
-<style>
- .config-reference-controls {
- display: flex;
- align-items: baseline;
- gap: 1rem;
- margin-top: 1rem;
- }
-
- .config-reference-filter {
- flex: 1;
- font: inherit;
- font-family: var(--sl-font-mono);
- font-size: var(--sl-text-sm);
- color: var(--sl-color-white);
- background: var(--sl-color-bg-inline-code);
- border: 1px solid var(--sl-color-hairline-light);
- border-radius: 0.4rem;
- padding: 0.5rem 0.75rem;
- }
-
- .config-reference-filter:focus {
- outline: 2px solid var(--sl-color-accent);
- outline-offset: -1px;
- }
-
- .config-reference-meta {
- margin: 0;
- font-size: var(--sl-text-xs);
- color: var(--sl-color-gray-3);
- white-space: nowrap;
- }
-
- .config-reference-title {
- margin-top: 2rem;
- }
-
- .config-reference-list {
- list-style: none;
- padding: 0;
- margin: 0.75rem 0 0;
- }
-
- .config-reference-row {
- padding: 0.6rem 0;
- border-bottom: 1px solid var(--sl-color-hairline);
- }
-
- .config-reference-row[hidden] {
- display: none;
- }
-
- .config-reference-head {
- display: flex;
- flex-wrap: wrap;
- align-items: baseline;
- gap: 0.6rem;
- }
-
- .config-reference-key {
- font-weight: 600;
- }
-
- .config-reference-type {
- font-size: var(--sl-text-xs);
- color: var(--sl-color-gray-3);
- border: 1px solid var(--sl-color-hairline-light);
- border-radius: 0.3rem;
- padding: 0 0.35rem;
- }
-
- .config-reference-default {
- font-size: var(--sl-text-xs);
- color: var(--sl-color-gray-3);
- }
-
- .config-reference-desc {
- margin: 0.25rem 0 0;
- font-size: var(--sl-text-sm);
- color: var(--sl-color-gray-2);
- }
-
- .config-reference-values {
- display: inline-flex;
- flex-wrap: wrap;
- gap: 0.3rem;
- margin-inline-start: 0.4rem;
- }
-
- .config-reference-empty {
- margin-top: 1.5rem;
- color: var(--sl-color-gray-3);
- }
-</style>
-
-<script>
- for (const root of document.querySelectorAll('.config-reference')) {
- const filter = root.querySelector('.config-reference-filter');
- const meta = root.querySelector('.config-reference-meta');
- const empty = root.querySelector('.config-reference-empty');
- const sections = [...root.querySelectorAll('.config-reference-section')];
- const rows = [...root.querySelectorAll('.config-reference-row')];
- const countLabel = root.dataset.countLabel;
-
- filter?.addEventListener('input', () => {
- const terms = filter.value.trim().toLowerCase().split(/\s+/).filter(Boolean);
- let visible = 0;
-
- for (const row of rows) {
- const haystack = row.dataset.search ?? '';
- const match = terms.every((term) => haystack.includes(term));
- row.hidden = !match;
- if (match) visible += 1;
- }
-
- for (const section of sections) {
- section.hidden = !section.querySelector('.config-reference-row:not([hidden])');
- }
-
- if (meta) meta.textContent = `${visible} ${countLabel}`;
- if (empty) empty.hidden = visible > 0;
- });
- }
-</script>
diff --git a/website/src/components/DocsVersionSelect.astro b/website/src/components/DocsVersionSelect.astro
deleted file mode 100644
index 5ccd856c..00000000
--- a/website/src/components/DocsVersionSelect.astro
+++ /dev/null
@@ -1,84 +0,0 @@
----
-import versions from '../data/docs-versions.json';
-import { docsRoute, docsTargetHref } from '../docs-path';
-
-const route = docsRoute(Astro.url.pathname);
-const locale = route.locale ?? 'root';
-const labels = {
- root: { accessible: 'Documentation version', latest: 'Latest', preview: 'Preview' },
- ja: { accessible: 'ドキュメントのバージョン', latest: '最新', preview: 'プレビュー' },
- 'zh-cn': { accessible: '文档版本', latest: '最新', preview: '预览版' },
-}[locale];
-const scopes = versions.scopes;
----
-
-{route.isDocs && (
- <label class="docs-version-select">
- <span class="sr-only">{labels.accessible}</span>
- <select autocomplete="off" aria-label={labels.accessible}>
- <option
- value={docsTargetHref(route, 'stable', scopes)}
- selected={route.target === 'stable'}
- >
- {labels.latest}{' '}{versions.current}
- </option>
- <option
- value={docsTargetHref(route, 'preview', scopes)}
- selected={route.target === 'preview'}
- >
- {labels.preview}
- </option>
- {versions.versions
- .filter((entry) => entry.version !== versions.current || route.target === versions.current)
- .map((entry) => (
- <option
- value={docsTargetHref(route, entry.version, scopes)}
- selected={route.target === entry.version}
- >
- {entry.version}
- </option>
- ))}
- </select>
- </label>
-)}
-
-<script>
- for (const select of document.querySelectorAll<HTMLSelectElement>('.docs-version-select select')) {
- select.addEventListener('change', () => {
- globalThis.location.href = select.value;
- });
- }
-</script>
-
-<style>
- .docs-version-select {
- display: flex;
- min-width: 0;
- }
-
- select {
- width: 9.5rem;
- min-width: 0;
- border: 1px solid var(--sl-color-hairline);
- border-radius: 4px;
- padding: 0.4rem 1.6rem 0.4rem 0.55rem;
- background: var(--sl-color-bg-nav);
- color: var(--sl-color-gray-2);
- font: inherit;
- font-size: var(--sl-text-xs);
- font-weight: 700;
- text-overflow: ellipsis;
- }
-
- select:hover,
- select:focus {
- border-color: var(--sl-color-accent);
- color: var(--sl-color-accent-high);
- }
-
- @media (max-width: 38rem) {
- select {
- width: 7.5rem;
- }
- }
-</style>
diff --git a/website/src/components/Head.astro b/website/src/components/Head.astro
deleted file mode 100644
index dac83b81..00000000
--- a/website/src/components/Head.astro
+++ /dev/null
@@ -1,67 +0,0 @@
----
-import { docsVersion } from '../docs-path';
-
-const { head } = Astro.locals.starlightRoute;
-const version = docsVersion(Astro.url.pathname);
----
-
-{head.map(({ tag: Tag, attrs, content }) => <Tag {...attrs} set:html={content} />)}
-<meta data-pagefind-filter="version[content]" content={version} />
-{version !== 'stable' && <meta name="robots" content="noindex, nofollow" />}
-
-<script>
- const labels = (() => {
- const lang = document.documentElement.lang.toLowerCase();
- if (lang.startsWith('ja')) return { copy: 'リンクをコピー', copied: 'コピーしました' };
- if (lang.startsWith('zh')) return { copy: '复制链接', copied: '已复制' };
- return { copy: 'Copy link', copied: 'Copied' };
- })();
-
- function labelHeadingLinks(root: ParentNode = document) {
- for (const link of root.querySelectorAll<HTMLAnchorElement>('.sl-anchor-link')) {
- link.title = labels.copy;
- const section = link.querySelector('.sr-only')?.textContent;
- if (section) link.setAttribute('aria-label', `${labels.copy}: ${section}`);
- }
- }
-
- labelHeadingLinks();
- document.addEventListener('astro:page-load', () => labelHeadingLinks());
- document.addEventListener('click', async (event) => {
- if (
- event instanceof MouseEvent &&
- (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
- ) {
- return;
- }
-
- const target = event.target;
- if (!(target instanceof Element)) return;
- const link = target.closest('.sl-anchor-link');
- if (!(link instanceof HTMLAnchorElement) || !navigator.clipboard?.writeText) return;
-
- try {
- await navigator.clipboard.writeText(link.href);
- } catch {
- return;
- }
-
- link.querySelector('.heading-link-copy-feedback')?.remove();
- const feedback = document.createElement('span');
- feedback.className = 'heading-link-copy-feedback';
- feedback.setAttribute('aria-hidden', 'true');
- feedback.textContent = labels.copied;
- link.append(feedback);
- window.setTimeout(() => feedback.remove(), 1400);
-
- let status = document.querySelector<HTMLElement>('[data-heading-link-copy-status]');
- if (!status) {
- status = document.createElement('span');
- status.className = 'sr-only';
- status.setAttribute('role', 'status');
- status.dataset.headingLinkCopyStatus = '';
- document.body.append(status);
- }
- status.textContent = labels.copied;
- });
-</script>
diff --git a/website/src/components/Header.astro b/website/src/components/Header.astro
deleted file mode 100644
index cfa3d759..00000000
--- a/website/src/components/Header.astro
+++ /dev/null
@@ -1,99 +0,0 @@
----
-import config from 'virtual:starlight/user-config';
-
-import LanguageSelect from 'virtual:starlight/components/LanguageSelect';
-import Search from 'virtual:starlight/components/Search';
-import SiteTitle from 'virtual:starlight/components/SiteTitle';
-import SocialIcons from 'virtual:starlight/components/SocialIcons';
-import ThemeSelect from 'virtual:starlight/components/ThemeSelect';
-import DocsVersionSelect from './DocsVersionSelect.astro';
-import { docsRoute } from '../docs-path';
-
-const shouldRenderSearch =
- config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
-const isDocs = docsRoute(Astro.url.pathname).isDocs;
----
-
-<div class="header">
- <div class="title-wrapper sl-flex">
- <SiteTitle />
- </div>
- <div class="sl-flex print:hidden search-wrapper">
- {isDocs && <DocsVersionSelect />}
- {shouldRenderSearch && <Search />}
- </div>
- <div class="sl-hidden md:sl-flex print:hidden right-group">
- <div class="sl-flex social-icons">
- <SocialIcons />
- </div>
- <ThemeSelect />
- <LanguageSelect />
- </div>
-</div>
-
-<style>
- @layer starlight.core {
- .header {
- display: flex;
- gap: var(--sl-nav-gap);
- justify-content: space-between;
- align-items: center;
- height: 100%;
- }
-
- .title-wrapper {
- overflow: clip;
- padding: 0.25rem;
- margin: -0.25rem;
- min-width: 0;
- }
-
- .search-wrapper {
- align-items: center;
- gap: 0.75rem;
- min-width: 0;
- }
-
- .right-group,
- .social-icons {
- gap: 1rem;
- align-items: center;
- }
-
- .social-icons::after {
- content: "";
- height: 2rem;
- border-inline-end: 1px solid var(--sl-color-gray-5);
- }
-
- @media (min-width: 50rem) {
- :global(:root[data-has-sidebar]) {
- --__sidebar-pad: calc(2 * var(--sl-nav-pad-x));
- }
-
- :global(:root:not([data-has-toc])) {
- --__toc-width: 0rem;
- }
-
- .header {
- --__sidebar-width: max(0rem, var(--sl-content-inline-start, 0rem) - var(--sl-nav-pad-x));
- --__main-column-fr: calc(
- (
- 100% + var(--__sidebar-pad, 0rem) - var(--__toc-width, var(--sl-sidebar-width)) -
- (2 * var(--__toc-width, var(--sl-nav-pad-x))) - var(--sl-content-inline-start, 0rem) -
- var(--sl-content-width)
- ) / 2
- );
- display: grid;
- grid-template-columns:
- minmax(
- calc(var(--__sidebar-width) + max(0rem, var(--__main-column-fr) - var(--sl-nav-gap))),
- auto
- )
- 1fr
- auto;
- align-content: center;
- }
- }
- }
-</style>
diff --git a/website/src/components/MarketingLayout.astro b/website/src/components/MarketingLayout.astro
deleted file mode 100644
index 6db7e00d..00000000
--- a/website/src/components/MarketingLayout.astro
+++ /dev/null
@@ -1,274 +0,0 @@
----
-interface Props {
- title: string;
- description: string;
- canonicalPath: string;
- ogType?: 'website' | 'article';
- ogImage?: string;
- ogImageAlt?: string;
-}
-
-const {
- title,
- description,
- canonicalPath,
- ogType = 'website',
- ogImage = '/assets/og-card-v9.png',
- ogImageAlt = 'Herdr — run them anywhere, leave them running.',
-} = Astro.props;
-const canonicalUrl = new URL(canonicalPath, 'https://herdr.dev').toString();
-const ogImageUrl = new URL(ogImage, 'https://herdr.dev').toString();
----
-
-<!doctype html>
-<html lang="en">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>{title}</title>
- <meta name="description" content={description} />
- <meta name="theme-color" content="#f0eee9" />
- <link rel="canonical" href={canonicalUrl} />
-
- <meta property="og:type" content={ogType} />
- <meta property="og:site_name" content="Herdr" />
- <meta property="og:title" content={title} />
- <meta property="og:description" content={description} />
- <meta property="og:url" content={canonicalUrl} />
- <meta property="og:image" content={ogImageUrl} />
- <meta property="og:image:width" content="1200" />
- <meta property="og:image:height" content="630" />
- <meta property="og:image:alt" content={ogImageAlt} />
-
- <meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:title" content={title} />
- <meta name="twitter:description" content={description} />
- <meta name="twitter:image" content={ogImageUrl} />
- <meta name="twitter:image:alt" content={ogImageAlt} />
-
- <link rel="icon" href="/favicon.ico" sizes="48x48" />
- <link rel="icon" type="image/png" sizes="192x192" href="/assets/favicon.png" />
- <link rel="apple-touch-icon" href="/assets/logo.png" />
- <link rel="preload" href="/assets/jbm.woff2" as="font" type="font/woff2" crossorigin />
- <script>
- (function () {
- var saved = localStorage.getItem("herdr-palette");
- var system = window.matchMedia("(prefers-color-scheme: dark)").matches
- ? "tokyo-night"
- : "tokyo-night-day";
- document.documentElement.setAttribute("data-palette", saved || system);
- })();
- </script>
- <link rel="stylesheet" href="/css/style.css?v=41" />
- </head>
- <body>
- <header class="site-header">
- <nav class="nav" aria-label="Primary navigation">
- <a class="brand" href="/" aria-label="Herdr home">
- <span class="brand-logo" aria-hidden="true"></span>
- <span>herdr</span>
- </a>
- <details class="nav-menu">
- <summary class="nav-menu-button" aria-label="Open navigation">
- <span></span>
- <span></span>
- <span></span>
- </summary>
- <div class="nav-menu-panel">
- <a href="/">Home</a>
- <a href="/compare/">Compare</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- <a href="/docs/quick-start/">Quick start</a>
- <a href="/docs/">Docs</a>
- <a href="/docs/socket-api/">API</a>
- <a href="/docs/install/">Install</a>
- <a href="https://github.com/herdrdev/herdr">GitHub</a>
- </div>
- </details>
- <div class="nav-links">
- <a href="/">Home</a>
- <a href="/compare/">Compare</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- <a href="/docs/quick-start/">Quick start</a>
- <a href="/docs/">Docs</a>
- <a href="/docs/socket-api/">API</a>
- </div>
- <div class="nav-tools">
- <a class="nav-icon-link" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub">
- <svg viewBox="0 0 16 16" aria-hidden="true">
- <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" />
- </svg>
- </a>
- <a class="nav-icon-link" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true">
- <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" />
- </svg>
- </a>
- <a class="nav-cta" href="/docs/install/">Install</a>
- </div>
- </nav>
- </header>
-
- <slot />
-
- <div class="theme-hint" id="theme-hint" title="Press / or t to switch theme">
- <span class="theme-hint-dot"></span>
- <span class="theme-hint-label" id="theme-hint-label">light</span>
- <span class="theme-hint-key">[/]</span>
- </div>
-
- <div class="theme-overlay" id="theme-overlay" hidden>
- <div class="theme-overlay-panel" role="dialog" aria-label="Theme switcher" aria-modal="true">
- <div class="theme-overlay-title">settings</div>
- <div class="theme-overlay-tabs"><span class="active">theme</span></div>
- <div class="theme-overlay-list" id="theme-overlay-list" role="listbox" aria-label="Themes">
- <div class="theme-sep"><span>dark</span></div>
- <button type="button" role="option" data-value="catppuccin">catppuccin</button>
- <button type="button" role="option" data-value="terminal">terminal</button>
- <button type="button" role="option" data-value="tokyo-night">tokyo night</button>
- <button type="button" role="option" data-value="dracula">dracula</button>
- <button type="button" role="option" data-value="nord">nord</button>
- <button type="button" role="option" data-value="gruvbox">gruvbox</button>
- <button type="button" role="option" data-value="one-dark">one dark</button>
- <button type="button" role="option" data-value="solarized">solarized</button>
- <button type="button" role="option" data-value="kanagawa">kanagawa</button>
- <button type="button" role="option" data-value="rose-pine">rose pine</button>
- <button type="button" role="option" data-value="vesper">vesper</button>
- <div class="theme-sep"><span>light</span></div>
- <button type="button" role="option" data-value="catppuccin-latte">catppuccin latte</button>
- <button type="button" role="option" data-value="tokyo-night-day">tokyo day</button>
- <button type="button" role="option" data-value="gruvbox-light">gruvbox light</button>
- <button type="button" role="option" data-value="one-light">one light</button>
- <button type="button" role="option" data-value="solarized-light">solarized light</button>
- <button type="button" role="option" data-value="kanagawa-lotus">kanagawa lotus</button>
- <button type="button" role="option" data-value="rose-pine-dawn">rose pine dawn</button>
- </div>
- <div class="theme-overlay-footer">
- <span class="theme-overlay-hints"><span class="key">↑↓</span> select</span>
- <span class="theme-overlay-actions"><span class="theme-apply-btn">↵ apply</span><button class="theme-close-btn" type="button" id="theme-close-btn">esc close</button></span>
- </div>
- </div>
- </div>
-
- <script>
- (function () {
- var overlay = document.getElementById("theme-overlay");
- var list = document.getElementById("theme-overlay-list");
- var hintLabel = document.getElementById("theme-hint-label");
- if (!overlay || !list) return;
- var options = Array.prototype.slice.call(list.querySelectorAll("[role='option']"));
- var media = window.matchMedia("(prefers-color-scheme: dark)");
- var saved = localStorage.getItem("herdr-palette") || "";
- var committed = saved || defaultPalette();
-
- function defaultPalette() {
- return media.matches ? "tokyo-night" : "tokyo-night-day";
- }
-
- function setPalette(value) {
- document.documentElement.setAttribute("data-palette", value || defaultPalette());
- }
-
- function updateUI(value) {
- var activeValue = value || defaultPalette();
- options.forEach(function (opt) {
- opt.setAttribute("aria-selected", String(opt.dataset.value === activeValue));
- });
- var active = options.find(function (opt) { return opt.dataset.value === activeValue; });
- if (hintLabel && active) hintLabel.textContent = active.textContent.trim();
- }
-
- function openOverlay() {
- overlay.hidden = false;
- document.body.style.overflow = "hidden";
- committed = localStorage.getItem("herdr-palette") || defaultPalette();
- updateUI(committed);
- var active = list.querySelector("[aria-selected='true']") || options[0];
- if (active) active.focus();
- }
-
- function closeOverlay() {
- overlay.hidden = true;
- document.body.style.overflow = "";
- }
-
- function toggleOverlay() {
- if (overlay.hidden) openOverlay();
- else closeOverlay();
- }
-
- function preview(index) {
- if (index < 0 || index >= options.length) return;
- setPalette(options[index].dataset.value);
- updateUI(options[index].dataset.value);
- options[index].focus();
- }
-
- function commit(value) {
- setPalette(value);
- localStorage.setItem("herdr-palette", value);
- updateUI(value);
- closeOverlay();
- }
-
- function revert() {
- setPalette(committed);
- updateUI(committed);
- closeOverlay();
- }
-
- media.addEventListener("change", function () {
- if (!localStorage.getItem("herdr-palette")) {
- setPalette("");
- updateUI("");
- }
- });
-
- options.forEach(function (opt, idx) {
- opt.addEventListener("click", function () { commit(opt.dataset.value); });
- opt.addEventListener("mouseenter", function () { preview(idx); });
- });
-
- document.addEventListener("keydown", function (e) {
- if ((e.key === "t" || e.key === "/") && !e.ctrlKey && !e.metaKey && !e.altKey) {
- var tag = document.activeElement && document.activeElement.tagName;
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
- e.preventDefault();
- toggleOverlay();
- return;
- }
- if (overlay.hidden) return;
- var idx = options.indexOf(document.activeElement);
- if (e.key === "ArrowDown") {
- e.preventDefault();
- preview(idx >= 0 ? Math.min(options.length - 1, idx + 1) : 0);
- } else if (e.key === "ArrowUp") {
- e.preventDefault();
- preview(idx >= 0 ? Math.max(0, idx - 1) : options.length - 1);
- } else if (e.key === "Enter" && idx >= 0) {
- e.preventDefault();
- commit(options[idx].dataset.value);
- } else if (e.key === "Escape") {
- e.preventDefault();
- revert();
- }
- });
-
- var themeHint = document.getElementById("theme-hint");
- if (localStorage.getItem("herdr-theme-hint-seen") === "1") {
- themeHint.classList.add("is-seen");
- }
- themeHint.addEventListener("mouseenter", function () {
- localStorage.setItem("herdr-theme-hint-seen", "1");
- themeHint.classList.add("is-seen");
- }, { once: true });
- themeHint.addEventListener("click", toggleOverlay);
- document.getElementById("theme-close-btn").addEventListener("click", revert);
- setPalette(saved);
- updateUI(saved);
- })();
- </script>
- </body>
-</html>
diff --git a/website/src/components/Search.astro b/website/src/components/Search.astro
deleted file mode 100644
index cceeed34..00000000
--- a/website/src/components/Search.astro
+++ /dev/null
@@ -1,52 +0,0 @@
----
-import StarlightSearch from '@astrojs/starlight/components/Search.astro';
-import { docsVersion } from '../docs-path';
-
-const version = docsVersion(Astro.url.pathname);
----
-
-<version-search data-version={version}>
- <StarlightSearch />
-</version-search>
-
-<script>
- class VersionSearch extends HTMLElement {
- observer?: MutationObserver;
-
- connectedCallback() {
- const version = this.dataset.version;
- if (!version) return;
-
- const selectVersion = () => {
- const checkbox = this.querySelector<HTMLInputElement>(
- `.pagefind-ui__filter-checkbox[name="version"][value="${version}"]`,
- );
- if (!checkbox) return false;
- if (!checkbox.checked) checkbox.click();
- this.observer?.disconnect();
- return true;
- };
-
- if (selectVersion()) return;
- // Starlight does not expose its PagefindUI instance, so wait for Pagefind's filter control.
- this.observer = new MutationObserver(selectVersion);
- this.observer.observe(this, { childList: true, subtree: true });
- }
-
- disconnectedCallback() {
- this.observer?.disconnect();
- }
- }
-
- customElements.define('version-search', VersionSearch);
-</script>
-
-<style>
- version-search {
- display: contents;
- }
-
- version-search :global(.pagefind-ui__filter-panel) {
- display: none;
- }
-</style>
diff --git a/website/src/components/Sidebar.astro b/website/src/components/Sidebar.astro
deleted file mode 100644
index 08d31f79..00000000
--- a/website/src/components/Sidebar.astro
+++ /dev/null
@@ -1,53 +0,0 @@
----
-import MobileMenuFooter from 'virtual:starlight/components/MobileMenuFooter';
-import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
-import SidebarSublist from '@astrojs/starlight/components/SidebarSublist.astro';
-import versions from '../data/docs-versions.json';
-import { docsRoute, docsTargetHref } from '../docs-path';
-
-const { sidebar } = Astro.locals.starlightRoute;
-const pathname = Astro.url.pathname;
-const route = docsRoute(pathname);
-const scopedSidebar = route.target === 'stable' ? sidebar : rewriteSidebar(sidebar);
-
-function rewriteSidebar(entries) {
- return entries.flatMap((entry) => {
- if (entry.type === 'link') {
- const linkRoute = docsRoute(entry.href);
- if (!linkRoute.isDocs) return [entry];
- if (linkRoute.target !== 'stable') {
- return linkRoute.target === route.target
- ? [{ ...entry, isCurrent: samePath(entry.href, pathname) }]
- : [];
- }
-
- const localeKey = route.locale ?? 'root';
- const availablePages = versions.scopes[route.target]?.locales[localeKey] ?? [];
- if (!availablePages.includes(linkRoute.page)) return [];
-
- const href = docsTargetHref({ ...linkRoute, locale: route.locale }, route.target, versions.scopes);
- return [{ ...entry, href, isCurrent: samePath(href, pathname) }];
- }
-
- const rewrittenEntries = rewriteSidebar(entry.entries);
- if (rewrittenEntries.length === 0) return [];
- return [{ ...entry, entries: rewrittenEntries }];
- });
-}
-
-function samePath(left, right) {
- return stripTrailingSlash(left) === stripTrailingSlash(right);
-}
-
-function stripTrailingSlash(path) {
- return path.length > 1 ? path.replace(/\/$/, '') : path;
-}
----
-
-<SidebarPersister>
- <SidebarSublist sublist={scopedSidebar} />
-</SidebarPersister>
-
-<div class="md:sl-hidden">
- <MobileMenuFooter />
-</div>
diff --git a/website/src/components/SiteLayout.astro b/website/src/components/SiteLayout.astro
deleted file mode 100644
index f056458c..00000000
--- a/website/src/components/SiteLayout.astro
+++ /dev/null
@@ -1,223 +0,0 @@
----
-/* The chassis every non-docs page shares: one dark ground, the framed grid,
- the same nav and footer as the homepage. Pages supply their own <main>.
- Docs keep Starlight's shell and are themed through src/styles/starlight.css. */
-interface Props {
- title: string;
- description: string;
- canonicalPath: string;
- ogType?: 'website' | 'article';
- ogImage?: string;
- ogImageAlt?: string;
-}
-
-const {
- title,
- description,
- canonicalPath,
- ogType = 'website',
- ogImage = '/assets/og-card-v9.png',
- ogImageAlt = 'Herdr — run them anywhere, leave them running.',
-} = Astro.props;
-
-import { fmt, releaseVersion, siteStats } from '../site-data';
-
-const canonicalUrl = new URL(canonicalPath, 'https://herdr.dev').toString();
-const ogImageUrl = new URL(ogImage, 'https://herdr.dev').toString();
-const year = new Date().getFullYear();
-
-/* Same build-time source the homepage uses, so the nav count and the footer
- version agree across every page without being written down twice. */
-const { starCount } = await siteStats();
-const version = await releaseVersion();
-const facts = version ? `v${version} · Apache 2.0` : 'Apache 2.0';
----
-
-<!doctype html>
-<html lang="en" data-palette="catppuccin" data-mode="ink">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>{title}</title>
- <meta name="description" content={description} />
- <meta name="theme-color" content="#17171a" />
- <link rel="canonical" href={canonicalUrl} />
-
- <meta property="og:type" content={ogType} />
- <meta property="og:site_name" content="Herdr" />
- <meta property="og:title" content={title} />
- <meta property="og:description" content={description} />
- <meta property="og:url" content={canonicalUrl} />
- <meta property="og:image" content={ogImageUrl} />
- <meta property="og:image:width" content="1200" />
- <meta property="og:image:height" content="630" />
- <meta property="og:image:alt" content={ogImageAlt} />
-
- <meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:title" content={title} />
- <meta name="twitter:description" content={description} />
- <meta name="twitter:image" content={ogImageUrl} />
- <meta name="twitter:image:alt" content={ogImageAlt} />
-
- <link rel="icon" href="/favicon.ico" sizes="48x48" />
- <link rel="icon" type="image/png" sizes="192x192" href="/assets/favicon.png" />
- <link rel="apple-touch-icon" href="/assets/logo.png" />
- <link rel="preload" href="/assets/jbm.woff2?v=2" as="font" type="font/woff2" crossorigin />
- <link rel="preconnect" href="https://fonts.googleapis.com" />
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
- <link
- href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&family=Inter:wght@400;500;600&display=swap"
- rel="stylesheet"
- />
- <script is:inline>
- /* Ground selection, shared with the docs — see index.html for the
- reasoning. Starlight's `starlight-theme` key is the source of truth;
- `auto` is treated as dark so the default never follows the OS. */
- window.herdrGround = {
- read: function () {
- try {
- return localStorage.getItem('starlight-theme') === 'light' ? 'paper' : 'ink';
- } catch (e) {
- return 'ink';
- }
- },
- apply: function (mode) {
- var root = document.documentElement;
- root.setAttribute('data-mode', mode);
- root.setAttribute('data-palette', mode === 'paper' ? 'solarized-light' : 'catppuccin');
- return mode;
- },
- save: function (mode) {
- try {
- localStorage.setItem('starlight-theme', mode === 'paper' ? 'light' : 'dark');
- } catch (e) {}
- },
- };
- window.herdrGround.apply(window.herdrGround.read());
- </script>
- <link rel="stylesheet" href="/css/style.css?v=59" />
- <link rel="stylesheet" href="/css/site.css?v=64" />
- </head>
- <body class="site">
- <div class="hd-frame">
- <nav class="hd-nav">
- <a class="lock" href="/"><span class="ram"></span><b>herdr</b></a>
- <div class="sp"></div>
- <a class="lnk" href="/docs/">Docs</a>
- <a class="lnk" href="/plugins/">Plugins</a>
- <a class="lnk" href="/blog/">Blog</a>
- <a class="lnk" href="/compare/">Compare</a>
- <a class="ico wide" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub — star count">
- <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" /></svg>
- <b data-stars>{fmt(starCount)}</b>
- </a>
- <a class="ico" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" /></svg>
- </a>
- <div class="mode">
- <button type="button" data-ground="ink" aria-pressed="true">ink</button>
- <button type="button" data-ground="paper" aria-pressed="false">paper</button>
- </div>
- <a class="btn" href="/docs/install/">Install</a>
- <button type="button" class="menu" id="nav-menu" aria-expanded="false" aria-controls="nav-sheet" aria-label="Menu">
- <span></span><span></span><span></span>
- </button>
- </nav>
-
- <div class="sheet" id="nav-sheet">
- <a href="/docs/">Docs</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- <a href="/compare/">Compare</a>
- <a href="https://x.com/herdrdev">@herdrdev</a>
- <div class="sheet-ground">
- <span>Ground</span>
- <div class="mode">
- <button type="button" data-ground="ink" aria-pressed="true">ink</button>
- <button type="button" data-ground="paper" aria-pressed="false">paper</button>
- </div>
- </div>
- </div>
-
- <slot />
-
- <footer class="foot">
- <span class="ram"></span>
- <a href="/docs/">docs</a>
- <a href="/plugins/">plugins</a>
- <a href="/blog/">blog</a>
- <a href="/compare/">compare</a>
- <span>built in the terminal · © {year} Herdr, Inc.</span>
- <span class="fact">{facts}</span>
- <span class="out">
- <a class="ico" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub">
- <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" /></svg>
- </a>
- <a class="ico" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" /></svg>
- </a>
- <a href="mailto:hey@herdr.dev">hey@herdr.dev</a>
- </span>
- </footer>
- </div>
-
- <script is:inline>
- (function () {
- var buttons = document.querySelectorAll('[data-ground]');
- function paint(mode) {
- window.herdrGround.apply(mode);
- buttons.forEach(function (b) {
- b.setAttribute('aria-pressed', String(b.dataset.ground === mode));
- });
- }
- buttons.forEach(function (b) {
- b.addEventListener('click', function () {
- window.herdrGround.save(b.dataset.ground);
- paint(b.dataset.ground);
- });
- });
- paint(window.herdrGround.read());
- })();
-
- /* nav sheet — the links, the account and the ground toggle that don't
- fit the bar on a phone */
- (function () {
- var btn = document.getElementById('nav-menu');
- var sheet = document.getElementById('nav-sheet');
- if (!btn || !sheet) return;
- function set(open) {
- sheet.classList.toggle('open', open);
- btn.setAttribute('aria-expanded', String(open));
- }
- btn.addEventListener('click', function (event) {
- event.stopPropagation();
- set(!sheet.classList.contains('open'));
- });
- /* the ground buttons live in the sheet, so a tap inside must not close
- it — only taps on the page behind do */
- document.addEventListener('click', function (event) {
- if (!sheet.contains(event.target)) set(false);
- });
- document.addEventListener('keydown', function (event) {
- if (event.key === 'Escape') set(false);
- });
- })();
-
- /* The nav count is baked at build, which can be a deploy behind. Refresh
- it from the same snapshot so the number is current on every page. No
- count-up here — this is chrome, not the argument the homepage makes. */
- fetch('https://assets.herdr.dev/stats/stats.json', { headers: { accept: 'application/json' } })
- .then(function (r) {
- return r.ok ? r.json() : null;
- })
- .then(function (d) {
- if (!d || !d.stars || typeof d.stars.total !== 'number') return;
- var text = d.stars.total.toLocaleString('en-US');
- document.querySelectorAll('[data-stars]').forEach(function (el) {
- el.textContent = text;
- });
- })
- .catch(function () {});
- </script>
- </body>
-</html>
diff --git a/website/src/components/SiteTitle.astro b/website/src/components/SiteTitle.astro
deleted file mode 100644
index 3e5af0a3..00000000
--- a/website/src/components/SiteTitle.astro
+++ /dev/null
@@ -1,95 +0,0 @@
----
-import { docsRoute } from '../docs-path';
-
-const { siteTitle, siteTitleHref, locale } = Astro.locals.starlightRoute;
-const route = docsRoute(Astro.url.pathname);
-const localePrefix = locale ? `/${locale}` : '';
-const targetSegment = route.target === 'stable' ? '' : `/${route.target}`;
-const docsHref = `${localePrefix}/docs${targetSegment}/`;
----
-
-<div class="title-row sl-flex">
- <a href={siteTitleHref} class="site-title sl-flex">
- <span class="docs-brand-logo" aria-hidden="true"></span>
- <span translate="no">{siteTitle}</span>
- </a>
- <nav class="title-nav" aria-label="Primary">
- <a href={docsHref}>Docs</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- </nav>
-</div>
-
-<style>
- @layer starlight.core {
- .title-row {
- align-items: center;
- gap: 1rem;
- min-width: 0;
- }
-
- .site-title {
- align-items: center;
- gap: 0.55rem;
- font-family: var(--sl-font-mono);
- font-size: var(--sl-text-h4);
- font-weight: 700;
- letter-spacing: -0.04em;
- color: var(--sl-color-white);
- text-decoration: none;
- white-space: nowrap;
- min-width: 0;
- transition: color 120ms ease;
- }
-
- .docs-brand-logo {
- position: relative;
- display: inline-block;
- width: 32px;
- height: 32px;
- flex: 0 0 auto;
- border: 1px solid var(--sl-color-hairline);
- border-radius: 4px;
- background: var(--sl-color-bg-nav);
- }
-
- .docs-brand-logo::before {
- content: "";
- position: absolute;
- inset: 2px;
- background: var(--sl-color-white);
- -webkit-mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
- mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
- }
-
- span:not(.docs-brand-logo) {
- overflow: hidden;
- }
-
- .title-nav {
- display: flex;
- align-items: baseline;
- gap: 0.75rem;
- font-size: var(--sl-text-sm);
- font-weight: 600;
- line-height: 1;
- }
-
- .title-nav a {
- color: var(--sl-color-white);
- text-decoration: none;
- transition: color 120ms ease;
- }
-
- .site-title:hover,
- .title-nav a:hover {
- color: var(--sl-color-accent-high);
- }
-
- @media (max-width: 35rem) {
- .title-nav {
- display: none;
- }
- }
- }
-</style>
diff --git a/website/src/content.config.ts b/website/src/content.config.ts
deleted file mode 100644
index 88291349..00000000
--- a/website/src/content.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { defineCollection, z } from 'astro:content';
-import { glob } from 'astro/loaders';
-import { docsLoader } from '@astrojs/starlight/loaders';
-import { docsSchema } from '@astrojs/starlight/schema';
-import { docsPath } from './docs-path';
-
-export const collections = {
- docs: defineCollection({ loader: docsLoader({ generateId: docsPath }), schema: docsSchema() }),
- blog: defineCollection({
- loader: glob({ pattern: '*.md', base: './src/content/blog' }),
- schema: z.object({
- title: z.string(),
- description: z.string(),
- date: z.coerce.date(),
- draft: z.boolean().default(false),
- /* description is always used for meta and OG; set false when it should
- not also print as a subtitle under the title */
- lede: z.boolean().default(true),
- ogImage: z.string().optional(),
- }),
- }),
-};
diff --git a/website/src/content/blog/coding-agents-are-becoming-runtimes.md b/website/src/content/blog/coding-agents-are-becoming-runtimes.md
deleted file mode 100644
index 3628f4ec..00000000
--- a/website/src/content/blog/coding-agents-are-becoming-runtimes.md
+++ /dev/null
@@ -1,166 +0,0 @@
----
-title: Coding agents are becoming runtimes
-description: Coding agent CLIs are becoming developer infrastructure. Project instructions, lifecycle state, hooks, and terminal runtimes need shared contracts.
-date: 2026-06-10
-draft: false
----
-
-Coding agents started as chat interfaces that could edit code. Now they live inside repositories, terminals, editors, CI jobs, remote machines, mobile shells, multiplexers, and custom wrappers. They read project instructions. They run commands. They ask for permission. They spawn subagents. They pause, resume, compact, fail, recover, and keep working while the developer does something else.
-
-That is runtime behavior.
-
-The model can be proprietary. The hosted API can be proprietary. The subscription can be priced however the lab needs to price it. That part belongs to the companies building the models.
-
-But the CLI that runs inside a developer's terminal is part of the developer environment. It sits next to shells, language servers, package managers, test runners, terminals, editors, and multiplexers. Developers will compose it with the rest of their tools whether vendors plan for that or not.
-
-That is where the industry needs to be more careful.
-
-## We have seen this drift before
-
-Software already has too many places where the same idea fractured into incompatible files and conventions.
-
-JavaScript has `package.json`, then layers of package-manager lockfiles and workspace formats. Rust has `Cargo.toml`, which is refreshingly predictable. Python has lived through `requirements.txt`, `setup.py`, `setup.cfg`, `Pipfile`, `poetry.lock`, `pyproject.toml`, and tool-specific sections inside the same TOML file. Editors have their own settings. CI systems have their own YAML. Formatters and linters each add another little contract.
-
-Some of that is natural. Tools have different jobs.
-
-But the cost is real. Every repository becomes a map of overlapping conventions. Every new tool needs to learn which file matters, which one wins, and which one is legacy but still active.
-
-Agent CLIs are young enough that we can avoid repeating the worst version of that.
-
-Project instructions are the clearest example. [AGENTS.md](https://agents.md/) is trying to give coding agents one predictable place to read repository guidance. It describes itself as "a simple, open format for guiding coding agents" and says it is used by more than 60,000 open-source projects.
-
-The shape is simple:
-
-```text
-one repository
-one shared instruction file
-many coding agents
-```
-
-Claude Code still stays on [`CLAUDE.md`, not `AGENTS.md`](https://docs.anthropic.com/en/docs/claude-code/memory#agents-md). The official workaround is to create a `CLAUDE.md` that imports `AGENTS.md`, or to symlink one file to the other.
-
-That workaround works, and it is how standards drift begins.
-
-First there is one extra file. Then every agent has a native file. Then every repository grows a compatibility layer. Then teams spend time keeping duplicated intent in sync.
-
-Nobody loses a production database because a repo has two instruction files. The cost is smaller and more constant: duplicated intent, stale guidance, and another convention every tool has to learn.
-
-## The terminal is the shared surface
-
-There is another debate happening around access and third-party tools.
-
-Coding agents made per-token pricing feel very different. A chat session can be expensive. A coding agent can run tools, read files, loop, spawn work, and burn through a lot more context. So the labs started selling subscriptions with usage limits: some explicit, some soft, some hourly, some weekly, some hard to reason about from the outside.
-
-Then developers started doing what developers always do. They put the model behind the tool they preferred.
-
-That is where the Claude ecosystem became a useful case study. People used Claude subscriptions through third-party tools such as OpenClaw and OpenCode. Anthropic pushed back. Today Anthropic documents that [Claude Code can use Pro and Max subscriptions](https://support.claude.com/en/articles/11145838-use-claude-code-with-your-pro-or-max-plan), while [Claude paid plans and API access are separate products](https://support.claude.com/en/articles/9876003-i-have-a-paid-claude-subscription-pro-max-team-or-enterprise-plans-why-do-i-have-to-pay-separately-to-use-the-claude-api-and-console). Anthropic also introduced a separate [Agent SDK credit](https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan) for programmatic and third-party Agent SDK usage. Zed summarized the practical effect well: first-party Claude usage and third-party agent or SDK usage now draw from different pools.
-
-Anthropic can make that decision. They own the API. They own the subscription terms. Compute is expensive, and a first-party interactive CLI has different economics from arbitrary programmatic tools running through an SDK or protocol adapter.
-
-The developer-tooling question remains: what does a developer actually own—the subscription, the API spend, the model access, or the runtime where the agent works?
-
-When an agent runs in a terminal, it is no longer only a hosted product experience. It is a process in a developer environment. Developers will put that process in Herdr, Zed, tmux, SSH sessions, CI jobs, containers, and scripts. They will supervise it. They will route it. They will build workflows around it.
-
-The terminal is where ownership gets shared.
-
-That does not mean vendors lose the right to build first-party experiences. It means the CLI surface needs stable contracts because it has become infrastructure other tools depend on.
-
-## Hooks are a symptom
-
-Hooks show the same tension.
-
-Most serious agent CLIs have hooks, plugins, or extensions now. That is good. The problem is that "hooks" can mean almost anything.
-
-Some hooks are policy gates. Some are notifications. Some modify tool calls. Some inject context. Some observe messages. Some run at session boundaries. Some run around tools but miss interruptions, permission resolutions, or the exact state an external supervisor needs.
-
-This matters because agent work is no longer a single request and response. A coding agent has a lifecycle.
-
-For external tools, the minimum lifecycle is small:
-
-```text
-working -> actively doing work
-blocked -> needs permission, input, recovery, or attention
-idle -> ready for the next instruction
-```
-
-The concrete shape could be small:
-
-```json
-{
- "session_id": "abc123",
- "state": "blocked",
- "reason": "permission_request",
- "source": "agent"
-}
-```
-
-Permission prompts, failed tools, interrupted generations, automated reviews, subagent handoffs, and waiting for the user all need to land somewhere coherent.
-
-Claude Code has a serious hook system, and Codex has its own shape too. Both are substantial, but each agent still defines its own boundary. A hook surface can be powerful and still fail to provide a portable lifecycle contract.
-
-OpenCode is closer to the shape orchestration tools need. Its [plugin documentation](https://opencode.ai/docs/plugins/) exposes session-level events such as `session.idle`, `session.status`, `session.error`, `permission.asked`, and `permission.replied`.
-
-pi, meanwhile, treats extensibility as a broader system. Its [extension documentation](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md) describes TypeScript extensions that can subscribe to lifecycle events, register tools, add commands, intercept behavior, render UI, persist state, and hot-reload from local extension directories.
-
-Those designs are worth praising because they treat the agent as something other tools can understand.
-
-## What Herdr sees from below
-
-Herdr sits below the agent.
-
-It owns terminal panes. It keeps processes alive. It lets developers switch between agents, inspect them, recover sessions, and operate multiple agent processes as one workspace.
-
-From that layer, runtime drift becomes very visible.
-
-Herdr's first useful agent detection path was screen reading. If an agent drew "working", "waiting for approval", or "done" in the terminal, Herdr could read the terminal state and classify the pane.
-
-That matched what humans saw, which made it useful. It also broke when agent UIs changed. If the fix lived inside the Herdr binary, users needed a full Herdr update just to recognize a new prompt or status line.
-
-Another tempting signal was terminal activity.
-
-```text
-screen changing -> probably working
-screen still -> maybe idle or blocked
-```
-
-Real agents break that quickly. A spinner can redraw while the meaningful state is blocked. A permission prompt can sit still while it is the most important thing in the pane. A subagent can produce activity while the parent session is waiting.
-
-Terminal activity is evidence. Lifecycle is stronger.
-
-Herdr now uses better signals where agents expose them, keeps screen evidence as a fallback, and ships hot-reloadable detection manifests so compatibility fixes do not always require a new Herdr binary. That is the practical bridge for today's ecosystem. The durable contract should come from agents themselves.
-
-## Runtime support should be visible
-
-Herdr can support agents in two broad ways.
-
-Some agents expose reliable lifecycle signals. Those can have verified lifecycle support.
-
-Other agents require observed detection through terminal output, screen evidence, manifests, and heuristics. That can work well, but it depends on UI behavior staying recognizable.
-
-Herdr will publish this as a per-agent support matrix: which agents expose verified lifecycle signals, and which agents require observed detection.
-
-This distinction should be public because it helps everyone.
-
-Users get honest expectations. Agent authors get a target. Tool builders get a vocabulary. The ecosystem rewards agents that expose their runtime state cleanly.
-
-Agents can keep their own plugin systems while standardizing the parts that should never have been product differentiation.
-
-## Standardize the boring parts
-
-Use one predictable project instruction format. Expose a small lifecycle contract. Make permission state observable. Make interruption state observable. Tie state to the session that is actually running. Document what external tools can rely on.
-
-Keep competing on models, UX, planning, context management, speed, pricing, safety, and taste.
-
-Do not compete on whether a repository needs five instruction files.
-
-Do not compete on whether an external tool can tell if an agent is blocked.
-
-Do not make every terminal runtime reverse-engineer every other terminal runtime.
-
-Coding agents are becoming infrastructure. The companies building them still own their products, but developers own their environments.
-
-Herdr is built from that position. The terminal is where these agents actually run. The runtime surface belongs to the developer workflow, and vendors share that space whether they design for it or not.
-
-Agents should make their basic contracts visible, durable, and boring.
-
-Then the rest of us can build.
diff --git a/website/src/content/blog/herdr-0-6-3.md b/website/src/content/blog/herdr-0-6-3.md
deleted file mode 100644
index 3abb5f5f..00000000
--- a/website/src/content/blog/herdr-0-6-3.md
+++ /dev/null
@@ -1,85 +0,0 @@
----
-title: "Herdr 0.6.3: session persistence, safer updates, and workspace navigation"
-description: "This one adds new persistence paths for updates, server restarts, and larger sessions."
-date: 2026-05-27
-draft: false
----
-
-## Persistence for the hard parts
-
-Keeping a session alive means handling several different cases: a detached client, a stopped server, terminal history replay, agent conversation restore, and an update handoff. Each protects a different part of the workspace.
-
-Herdr 0.6.3 improves three of those paths.
-
-### Agent restore after server restart
-
-When a Herdr server stops, normal pane processes stop with it. Native agent restore is the path for getting supported agent conversations back after that kind of restart.
-
-With `[session] resume_agents_on_restore = true`, Herdr can use official session references from supported integrations to relaunch Pi, Claude Code, Codex, OpenCode, and Hermes panes into their previous conversations.
-
-[Read the session restore docs](/docs/session-state/#native-agent-session-restore).
-
-### Pane screen history
-
-Pane screen history solves the visual half of restart recovery. When enabled, Herdr saves recent pane output and replays it into restored panes so the workspace does not come back as a set of empty terminals.
-
-It is useful for shells, logs, dev servers, and agent panes where recent output explains what was happening before the server stopped.
-
-[Read how pane history differs from live persistence](/docs/session-state/#what-survives).
-
-### Live handoff for updates
-
-Live handoff is the update path for supported running sessions. Instead of stopping the old server and killing pane processes, Herdr can ask the old server to transfer live PTY ownership to the updated server.
-
-It is currently experimental and opt-in with `herdr update --handoff` and `herdr --remote <host> --handoff`. That keeps the default path conservative while the feature gets more real-world coverage.
-
-[Read the live handoff docs](/docs/session-state/#live-handoff).
-
-For the technical background, read the deep dive: [Live updates without killing your terminal processes](/blog/live-updates-without-killing-your-terminal-processes/).
-
-## Session navigator
-
-Large Herdr sessions need fast movement. The new session navigator opens with `prefix+g` and gives you a searchable workspace, tab, and pane tree.
-
-At a glance, you can see the full tree of workspaces, tabs, and panes. Press `/` to fuzzy find by text. Press `b`, `w`, `i`, or `d` to filter by blocked, working, idle, or done panes. Press `a` or Backspace to clear the state filter.
-
-Use it to jump straight to the pane that needs attention without manually scanning the sidebar.
-
-<figure class="release-media">
- <video src="/assets/releases/v0.6.3/session-navigator.mp4" controls playsinline preload="metadata"></video>
- <figcaption>
- The session navigator shows workspaces, tabs, panes, and agent states in one searchable tree.
- </figcaption>
-</figure>
-
-## More terminal workflow polish
-
-Direct agent terminal attaches now have scrollback, so PageUp, PageDown, and mouse wheel scrolling work in the attach viewport when the running terminal app has not requested that input for itself.
-
-Herdr also gained better update and remote-bootstrap behavior for package-manager installs, more reliable event delivery under load, and fixes across agent detection, terminal colors, sound alerts, and integration lifecycle handling.
-
-## Pane metadata reporting
-
-The new `pane.report_metadata` socket method and `herdr pane report-metadata` CLI command let integrations and local hooks customize what Herdr shows for a pane.
-
-Once installed, an integration can report a title, visible agent name, compact status label, state label, and native session metadata without taking over unrelated lifecycle behavior.
-
-You can also use it from your own scripts. For example, a hook can mark a pane as running a deploy, rename a long-lived task, or ask an agent to report a more specific state for the work it is doing.
-
-```bash
-herdr pane report-metadata \
- --title "api deploy" \
- --agent-name "codex" \
- --state-label "reviewing logs" \
- --compact-status "deploy"
-```
-
-This gives integrations a supported way to make panes more readable while keeping Herdr's session and agent ownership rules intact.
-
-[Read the socket API docs](/docs/socket-api/).
-
-## Full notes
-
-This page highlights the product changes. The complete release notes remain on GitHub.
-
-[Open the 0.6.3 GitHub release](https://github.com/herdrdev/herdr/releases/tag/v0.6.3).
diff --git a/website/src/content/blog/herdr-is-joining-y-combinator.md b/website/src/content/blog/herdr-is-joining-y-combinator.md
deleted file mode 100644
index 3a9cfa3e..00000000
--- a/website/src/content/blog/herdr-is-joining-y-combinator.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-title: Herdr is joining Y Combinator. The runtime stays open.
-description: Herdr is joining Y Combinator. The runtime is Apache-2.0 and stays open, and here is what the funding is actually for.
-date: 2026-08-06
-draft: false
-lede: false
-ogImage: /assets/og-blog-yc-v1.png
----
-
-Hey everyone, it's Can, the only person behind Herdr. This post is about how I decided to change that.
-
-Four months ago I was looking for another job. Thinking about where to go career-wise. Thinking about software engineering and its future in general, my hobby projects, applications, whiteboard interviews (I still can't believe we do those). And at some point it hit me: I am the bottleneck.
-
-This is a management and engineering problem. I don't want to install an app or learn a new tool just to manage my agents and my development style. I want something that fits me. You know how every company releases their own agent these days? No, don't do that. Let my agent integrate with your product, don't offer me another agent.
-
-Same idea here. I didn't like what I tried, so why not build it? So I built a runtime. But what is a runtime?
-
-## Runtime
-
-CLI coding agents run in terminals, and terminals have always been our home: editing code (yes, nvim chads), running servers, navigating projects, maintaining CI, machines, configurations. It's the root. It's the connection. So agents need first-class primitives there.
-
-A terminal pane belongs to an agent. A pane belongs to a tab. Tabs belong to a project.
-
-They need to be persistent. We have agents running for hours now, sometimes days. And once you have the runtime, where they run stops mattering. **You should be able to run them anywhere and keep them running.**
-
-That's where Herdr was born. But a runtime needs an interface, so I built the TUI.
-
-## TUI
-
-The TUI is the UI I use every day, and it carried Herdr this far because it shows what I believe Herdr should do: track agents at a glance, divide work between projects instead of getting lost in a pile of agents, and alert you only when an agent actually needs you.
-
-Its biggest advantage, and the reason it stays first-class forever, is that it's bundled. Install Herdr on your VPS, ssh in, and your UI is already there. Or run `herdr --remote user@host` and it installs itself. Depending on your network speed, you're a couple of seconds away from an agent running. One command and you're in. Nothing beats that.
-
-Still, the TUI was never meant to be the only client. A runtime means people can build on top of it, and people did! A [Raycast extension](https://x.com/vladscale/status/2080195067088871582), a [Stream Deck with buttons for herdr](https://x.com/timvdhoorn/status/2067907258260795808), an [iOS app](https://x.com/imnotchalk/status/2077647387414384936) that drives a whole session from a phone. More than 500 plugins, one month after the marketplace released. I didn't build any of these.
-
-The TUI has its limits too. Some of the ideas in my head are hard to build inside a terminal, and I trust terminals, but Herdr will need more clients. More on that later.
-
-## Where we are now
-
-So a solo project reached **25k stars and 340k downloads**, and it became more than one person can carry.
-
-Herdr is joining <span style="color:#fb651e">Y Combinator, F26 batch</span>. I'm excited to make Herdr a company that builds a developer tool for anyone juggling agents all day. I want to build a small team: people who keep the runtime healthy, reliable, fast, easy to run anywhere, and more extensible, so you can do more while Herdr stays small.
-
-The runtime, what you use right now, stays free. Apache-2.0. That's why I recently switched it from AGPL to Apache: I want everyone to use Herdr freely.
-
-## Where we're going
-
-I want to build on top of the open Herdr runtime like everyone else. I'll keep supporting the open source while building the features people really need. The demand is already visible: multiple clients, a laptop, a VPS for the six-hour job, a sandbox for risky code and ephemeral agents. Herdr can run anywhere today, but those machines are disconnected. They should be connected.
-
-There are many more features in my head, but I don't want to rush. People keep telling me they love that Herdr stays lean, and that's what I want to protect. In an age where adding one more feature costs nothing, choosing what goes in the core is the most important decision, I believe. So the core stays small, and everything else stays possible through extensions: your style, your flows, your company's setup, your themes, your crazy ideas.
-
-Thank you for getting Herdr this far. Thanks for the support, for sharing the love. You have no idea how grateful I am.
-
-Anyway, back to work.
-
-![A ram, asleep above the clouds. Or working, hard to tell.](/assets/where-do-agents-run-while-you-sleep.png)
diff --git a/website/src/content/blog/live-updates-without-killing-your-terminal-processes.md b/website/src/content/blog/live-updates-without-killing-your-terminal-processes.md
deleted file mode 100644
index 6658c488..00000000
--- a/website/src/content/blog/live-updates-without-killing-your-terminal-processes.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-title: Live updates without killing your terminal processes
-description: Herdr can replace its server during an update while keeping pane processes alive.
-date: 2026-05-27
----
-
-Live handoff shipped in Herdr 0.6.3 as an experimental, opt-in update path. See the [live handoff docs](/docs/session-state/#live-handoff) for the user-facing behavior.
-
-Terminal multiplexers are supposed to protect long-running work from interruption. You start a server, run shells and tools inside panes, detach clients, reconnect later, and the work keeps going.
-
-Updating the multiplexer itself usually breaks that.
-
-That is normal for tools like tmux and Zellij. They are mature, stable, and their core job changes slowly. If the server/client protocol changes, the usual answer is to keep using the old server until you can restart it. That is annoying, but often acceptable.
-
-Herdr has a different problem. It is a terminal multiplexer, sure, but it is also an AI development workspace. It is new. I released it a few months ago, and we are at 2.6k stars on GitHub. It has more than 15k downloads according to GitHub release stats.
-
-It gets frequent fixes for agent detection (isn't it cool that we have all the labs building their own CLIs, plugins, and hooks in their own broken way?), terminal behavior, remote workflows, worktrees, mobile use, update flows, and integrations. Users should not have to choose between getting those fixes and killing every pane in a running session.
-
-Herdr needed to update like an app while preserving processes like a terminal multiplexer.
-
-## The update problem
-
-A persistent terminal multiplexer usually has at least two sides.
-
-The server owns the session. It owns pane state, PTYs, readers, writers, layout, buffers, sockets, and child process lifetime. The client is mostly a view and input path into that server.
-
-When a new binary changes the client/server protocol, the new client may not be able to talk to the old server. Restarting the server fixes that, but it also risks killing the pane processes. For a terminal multiplexer, that is the worst possible update path.
-
-This is not only a Herdr problem. I looked around because I assumed somebody had already solved it.
-
-Zellij has multiple long-running issues about upgrade pain: sessions appearing lost after upgrade, users being unable to attach to sessions from a previous version, requests for an `upgrade-session` flow, and requests to import sessions from previous versions. See [zellij#1255](https://github.com/zellij-org/zellij/issues/1255), [zellij#2943](https://github.com/zellij-org/zellij/issues/2943), [zellij#3371](https://github.com/zellij-org/zellij/issues/3371), [zellij#3420](https://github.com/zellij-org/zellij/issues/3420), [zellij#3449](https://github.com/zellij-org/zellij/issues/3449), and [zellij#4305](https://github.com/zellij-org/zellij/issues/4305). Zellij 0.44 added forward-compatible client/server support, which helps future clients connect to older running sessions, but that is still not replacing the running server while preserving live PTYs.
-
-Tmux has the same class of version-skew behavior. Users hit protocol mismatch errors, and the practical answer is to restart tmux, delay the update, or attach with the old binary through `/proc/<pid>/exe` where that exists. See [tmux#99](https://github.com/tmux/tmux/issues/99), [tmux#2189](https://github.com/tmux/tmux/issues/2189), [tmux#4356](https://github.com/tmux/tmux/issues/4356), and [tmux#4890](https://github.com/tmux/tmux/issues/4890).
-
-As far as I can tell, mainstream terminal multiplexers do not do in-place server binary replacement while keeping arbitrary live pane processes attached.
-
-That is a small breakthrough, but a real one.
-
-## The important detail is PTY ownership
-
-At first, the problem sounds like process migration. But no, that would be much harder.
-
-Herdr does not move the child processes. It moves ownership of the terminals those processes are already attached to.
-
-Each pane process talks to the slave side of a PTY. Herdr's server owns the master side. If the final master FD disappears, the child can lose I/O, receive HUP, or exit. But if the master FD stays alive and a new server takes over reading and writing it, the child process does not need to know the server changed.
-
-That changes the problem from “move a process” to “transfer open file descriptors and rebuild runtime ownership around them.”
-
-On Unix, that is possible with `SCM_RIGHTS`: one process can send open file descriptors to another process over a Unix socket.
-
-## The handoff
-
-The final shape is a two-server transaction.
-
-```text
-old server: pause PTY readers
-old server: snapshot pure app state
-old server: duplicate PTY master FDs
-old server: spawn new Herdr in import mode
-handoff: send manifest + FDs over a private Unix socket
-new server: restore state and rebuild pane runtimes
-new server: bind public sockets and report ready
-old server: commit and exit without killing pane process groups
-new server: unpause readers and continue
-```
-
-The old server does not just dump state and hope. It enters handoff mode, rejects new mutations, disconnects clients, and pauses every transferred PTY reader. That pause acknowledgement matters because only one server may actively read from a PTY at a time. If both servers read from the same master, output can be stolen by the wrong runtime.
-
-After readers are paused, the old server captures Herdr's normal session snapshot. That works because Herdr already separates pure application state from runtime ownership. `AppState` can be serialized. Pane runtimes, PTY handles, readers, writers, and detector loops are separate runtime objects.
-
-Then the old server creates a handoff manifest and sends the duplicated PTY master FDs to the new server.
-
-```text
-manifest = app snapshot + pane metadata + optional replay bytes
-FDs = duplicated PTY master file descriptors
-transport = private Unix socket + SCM_RIGHTS
-```
-
-The new server validates the manifest, checks the expected protocol and version, receives the FDs, restores `AppState`, constructs imported pane runtimes around the received PTY masters, binds the normal Herdr sockets, and reports ready.
-
-Only then does the old server commit. Before commit, any failure rolls back to the old server. After commit, the new server owns the panes and the old server exits without signaling the pane process groups.
-
-That commit boundary is the safety line.
-
-## Why Herdr could do it
-
-Herdr had the pieces already, mostly because of earlier architecture choices.
-
-The state model is separated from runtime ownership. Workspaces, tabs, panes, labels, focus, layout, and agent metadata live in serializable state. PTYs, child handles, reader threads, writer paths, resize state, and detectors live in runtime objects.
-
-The server/client boundary is explicit. Herdr already has a persistent server, reconnecting clients, local sockets, named sessions, remote attach flows, and documented [session state paths](/docs/session-state/). That made it possible to add a hidden import mode instead of rewriting the app around live upgrades.
-
-The terminal engine also helped with visual continuity. Herdr uses `libghostty-vt` for pane terminal state. For normal primary-screen panes, the old server can export recent ANSI history and the new server can seed that history before it starts reading future PTY bytes. That is not required for process survival, but it makes shells and dev servers look continuous after reconnect.
-
-Full-screen terminal apps are different. Herdr does not fake replay for alternate-screen panes like `nvim`, `btop`, or `htop`. Their processes survive the handoff, but the visual state is best effort until the app redraws. That is the honest trade-off.
-
-## The invariants
-
-Sending FDs was easier than making the transaction safe.
-
-These were the rules:
-
-- exactly one server may read each PTY at a time
-- every transferred reader must acknowledge pause before snapshot and replay capture
-- before commit, failure leaves the old server alive and owning the panes
-- after commit, the old server must not destructively drop transferred runtimes
-- no failure path may close the final PTY master FD
-- agent restore must not run during [live handoff](/docs/session-state/#live-handoff)
-- alternate-screen panes must stay live without pretending their screen was perfectly serialized
-
-The implementation was tested with shell panes, a Python HTTP server, `btop`, and `nvim` on Linux and macOS. The HTTP server kept serving requests across handoff. Shell panes accepted input after handoff. Full-screen TUIs stayed alive and redrew on a best-effort basis.
-
-## What this is not
-
-This is not checkpoint/restore. It does not survive a reboot. It does not migrate processes across machines. It does not preserve arbitrary process memory. It does not make every future internal state change automatically compatible.
-
-It is a same-machine Unix handoff. The running pane process stays attached to its PTY slave. The old Herdr server transfers the PTY master to the new Herdr server. The server binary changes; the pane process keeps running.
-
-## Why this is cool
-
-Herdr users often keep the exact kind of work open that should not be casually restarted: coding agents, dev servers, shells, REPLs, SSH sessions, debugging sessions, long builds, and local experiments.
-
-A terminal multiplexer should make that work safer, not make updates feel dangerous.
-
-The process inside the pane does not have to know an update happened.
diff --git a/website/src/content/blog/ten-agents-three-clients-95-percent-less-cpu.md b/website/src/content/blog/ten-agents-three-clients-95-percent-less-cpu.md
deleted file mode 100644
index 6aef6af1..00000000
--- a/website/src/content/blog/ten-agents-three-clients-95-percent-less-cpu.md
+++ /dev/null
@@ -1,157 +0,0 @@
----
-title: Ten agents, three clients, 95% less CPU
-description: Herdr stopped animating its sidebar, drawing hidden panes, and repainting unchanged frames during mouse movement. The busiest sessions gained the most.
-date: 2026-08-03
-ogImage: /assets/og-blog-frames-v1.png
-draft: false
----
-
-In workloads dominated by unnecessary rendering, total CPU for the Herdr server and its attached clients fell by 89 to 95 percent. The renderer still runs at the same speed. Herdr now asks it to draw fewer frames.
-
-The savings grow with the session. With one agent and one client, total CPU fell 91 percent. With ten agents producing background output and three clients, it fell 95 percent. Every frame the server skips is also one less frame to serialize, transmit, and apply in each client.
-
-We found all three changes without a profiler. The first started as a complaint and gave us a rule: motion should mean something changed.
-
-## The spinner was a complaint before it was a cost
-
-Herdr's job is to tell you which agent needs you. You run five, ten, twenty of them, and the sidebar is how you know where to look.
-
-So every working agent got a spinner. It seemed obvious at the time. Motion means alive, and an agent that is thinking should look like it is thinking.
-
-Run twenty agents and you get twenty things moving at once, all saying the same thing, none saying it is the one that needs you. The workspace list already carried state as coloured dots. The sidebar was the noisy half of the same information. People told us. We agreed.
-
-The first fix isolated spinner redraws to the status rectangle. Instead of rebuilding pane contents for every tick, the server reused the client's retained frame, patched the smaller result, and sent it. We had made the spinner about as cheap as possible. Then we removed it anyway. It was a design decision first; the CPU saving was a side effect.
-
-<figure class="pf">
- <div class="pf-2">
- <div class="pf-panel">
- <div class="pf-label"><span>0.7.5</span><b>3 spinners, 8fps</b></div>
- <div class="pf-row working"><span class="pf-mark pf-spin"><i>⠋</i><i>⠙</i><i>⠹</i><i>⠸</i></span><div><strong>herdr</strong><small>working</small></div></div>
- <div class="pf-row working"><span class="pf-mark pf-spin"><i>⠋</i><i>⠙</i><i>⠹</i><i>⠸</i></span><div><strong>web-dashboard</strong><small>working</small></div></div>
- <div class="pf-row blocked"><span class="pf-mark">◉</span><div><strong>llm-proxy</strong><small>blocked, needs you</small></div></div>
- <div class="pf-row working"><span class="pf-mark pf-spin"><i>⠋</i><i>⠙</i><i>⠹</i><i>⠸</i></span><div><strong>data-pipeline</strong><small>working</small></div></div>
- <div class="pf-row done"><span class="pf-mark">●</span><div><strong>docs</strong><small>done</small></div></div>
- </div>
- <div class="pf-panel">
- <div class="pf-label"><span>0.8.0</span><b>nothing moves</b></div>
- <div class="pf-row working"><span class="pf-mark">●</span><div><strong>herdr</strong><small>working</small></div></div>
- <div class="pf-row working"><span class="pf-mark">●</span><div><strong>web-dashboard</strong><small>working</small></div></div>
- <div class="pf-row blocked"><span class="pf-mark">◉</span><div><strong>llm-proxy</strong><small>blocked, needs you</small></div></div>
- <div class="pf-row working"><span class="pf-mark">●</span><div><strong>data-pipeline</strong><small>working</small></div></div>
- <div class="pf-row done"><span class="pf-mark">●</span><div><strong>docs</strong><small>done</small></div></div>
- </div>
- </div>
- <figcaption class="pf-cap">Both panels carry the same information. Only one of them lets you find the blocked agent without reading. The left panel is animating in your browser right now, which is the entire argument.</figcaption>
-</figure>
-
-Working state is now a static coloured mark. Entering the state still renders immediately, so a change catches your eye when it happens. Remaining in the state schedules no animation.
-
-That design change saved more CPU than we expected. The spinner woke the server on a timer, rendered the status surface, compared and prepared the frame, serialized it, sent it to every attached client, and made each client apply it. This happened roughly eight times a second for as long as any agent was working, even when the rest of the screen stayed unchanged.
-
-Removing the spinner removed all of it: the timer, the animation deadlines, the scans asking whether any workspace contained a working pane, the animation-only render causes, the frame patching. Master produces zero scheduled animation frames. One agent working with nothing else on screen went from 1.467 percent CPU to 0.133 on Linux, and from 3.280 to 0.265 on macOS.
-
-## The same rule, applied to output you cannot see
-
-The same rule applies to output from panes nobody can see.
-
-When a pane produced output, the PTY reader set a shared flag to say something had happened. That coalesced wakeups efficiently but discarded the source pane. By the time the server picked up the flag, it could not tell whether the pane was on screen. A background agent writing to a tab nobody was viewing still produced frames for every attached client.
-
-<figure class="pf">
- <div class="pf-2">
- <div class="pf-panel">
- <div class="pf-label"><span>0.7.5</span><b>a pane writes</b></div>
- <div class="pf-flow">
- <div class="pf-step"><b>dirty flag set</b><s>something changed, we do not know what</s></div>
- <div class="pf-arrow">│</div>
- <div class="pf-step"><b>render</b><s>no way to rule it out</s></div>
- <div class="pf-arrow">│</div>
- <div class="pf-step"><b>serialize, transmit</b><s>once per attached client</s></div>
- <div class="pf-arrow">│</div>
- <div class="pf-step pf-cost"><b>3 clients apply a frame</b><s>for a tab none of them are showing</s></div>
- </div>
- </div>
- <div class="pf-panel">
- <div class="pf-label"><span>0.8.0</span><b>a pane writes</b></div>
- <div class="pf-flow">
- <div class="pf-step"><b>request_pty(pane 7)</b><s>the source is kept</s></div>
- <div class="pf-arrow">│</div>
- <div class="pf-step"><b>can any client see pane 7?</b><s>tabs, zoom, popups, direct attaches</s></div>
- <div class="pf-fork">
- <div class="pf-step pf-stop"><em>├─ no</em><b>stop here</b><s>bytes already parsed, nothing drawn</s></div>
- <div class="pf-step"><em>└─ yes</em><b>render as before</b><s>visible output is still visible output</s></div>
- </div>
- </div>
- </div>
- </div>
- <figcaption class="pf-cap">Render requests now carry their source. Writes from one pane coalesce into a single entry, while simultaneous writes from different panes each keep their identity.</figcaption>
-</figure>
-
-Skipping the render does not drop output. The bytes have already been parsed, so terminal state, scrollback, cursor, OSC metadata and agent detection all stay current. Switching to that tab renders from the current state. Where the mapping is unknown, Herdr treats the pane as visible, because a wrong skip leaves a stale screen while a wrong render only costs some CPU.
-
-## Mouse movement should not redraw an unchanged frame
-
-Every mouse event reported that the view had changed. Pointer movement over a pane is forwarded to the application inside it, but Herdr's own frame is usually identical before and after. At 60 motion events per second, that meant roughly 60 server renders and 60 client frames per second, to draw the same picture sixty times.
-
-Herdr now tracks which of its own modes respond to hover: the global menu, context menus and the navigator. Outside those modes, movement alone repaints nothing. The events still reach the pane exactly as before.
-
-The benchmark counted both ends. In every measured round, on both builds, 1,680 motion packets were sent and all 1,680 arrived in the pane. Version 0.7.5 emitted around 56 to 60 frames per second doing it. Master emitted none. Linux CPU fell from 9.450 percent to 0.667.
-
-## Why three changes became ninety percent
-
-Skipping one server render also skips frame preparation, serialization, transmission, and frame handling in every attached client.
-
-More clients multiply the saving. Ten silent working panes with one client improved 78 percent. The same panes with three clients improved 91 percent.
-
-<figure class="pf">
- <div class="pf-panel">
- <div class="pf-label"><span>total CPU, server plus every attached client</span><b>linux</b></div>
- <div class="pf-bars">
- <div class="pf-bar-row">
- <div class="pf-bar-name">one silent working pane</div>
- <div class="pf-bar old"><span>0.7.5</span><i style="width:11.3%"></i><em>1.467%</em></div>
- <div class="pf-bar new"><span>0.8.0</span><i style="width:1%"></i><em>0.133%</em></div>
- </div>
- <div class="pf-bar-row">
- <div class="pf-bar-name">ten silent working panes, three clients</div>
- <div class="pf-bar old"><span>0.7.5</span><i style="width:33.2%"></i><em>4.316%</em></div>
- <div class="pf-bar new"><span>0.8.0</span><i style="width:3.1%"></i><em>0.400%</em></div>
- </div>
- <div class="pf-bar-row">
- <div class="pf-bar-name">ten panes, nine hidden writers, three clients</div>
- <div class="pf-bar old"><span>0.7.5</span><i style="width:100%"></i><em>13.014%</em></div>
- <div class="pf-bar new"><span>0.8.0</span><i style="width:4.7%"></i><em>0.617%</em></div>
- </div>
- <div class="pf-bar-row">
- <div class="pf-bar-name">passive mouse motion at 60Hz</div>
- <div class="pf-bar old"><span>0.7.5</span><i style="width:72.6%"></i><em>9.450%</em></div>
- <div class="pf-bar new"><span>0.8.0</span><i style="width:5.1%"></i><em>0.667%</em></div>
- </div>
- <div class="pf-bar-row">
- <div class="pf-bar-name">forty-nine hidden writers at 60Hz</div>
- <div class="pf-bar old"><span>0.7.5</span><i style="width:44.6%"></i><em>5.800%</em></div>
- <div class="pf-bar new"><span>0.8.0</span><i style="width:34.1%"></i><em>4.433%</em></div>
- </div>
- </div>
- </div>
- <figcaption class="pf-cap">macOS followed the same shape: 22.958 percent to 1.673 in the hidden-output case, and 14.857 to 13.498 with forty-nine hidden writers at 60Hz.</figcaption>
-</figure>
-
-On 0.7.5, adding hidden background output to a session cost 8.7 CPU points on Linux and 12.7 on macOS. On master the same activity costs 0.2 and 0.6, which is roughly the price of reading and parsing the bytes and nothing else.
-
-## Where it does not help
-
-Fifty panes, forty-nine of them writing at 60Hz, is about 2,940 terminal updates per second. Every one of them still has to be read from the PTY and parsed into terminal state, because that is what makes the pane correct when you switch to it. Suppressing frames cannot suppress terminal emulation.
-
-That case improved 23.6 percent on Linux and 9.1 on macOS. Visible output at 60Hz, in a pane you are watching, improved 33.9 percent on Linux and 2.7 on macOS. Idle sat at the measurement floor on both builds and deserves no percentage claim at all.
-
-The optimization targets unnecessary rendering. Output-heavy cases remain dominated by PTY reads and terminal parsing.
-
-## How this was measured
-
-We compared official 0.7.5 release binaries with hashed master builds on separate Linux and macOS machines, giving 54 isolated observations per operating system. Every run used a fresh named session, real attached clients in fixed 86 by 47 terminals, a five-second warmup and twenty-one-second samples. The figures show total CPU for the Herdr server plus every attached client.
-
-We paired every headline CPU result with a behavioural counter: scheduled frames per second for the sidebar, hidden-source skips for background output, and exact packet delivery counts for mouse motion. A CPU number on its own can be explained by a dozen things. A CPU number with a matching mechanism counter is harder to argue with.
-
-This compares a shipped release against master, so intervening changes and build environments are part of the comparison. The profiler evidence matches the mechanisms closely, but not every CPU point can be assigned to one commit.
-
-The work started with people saying the sidebar was too busy, along with bug reports and performance reports from people running far stranger sessions than we test. Keep them coming, and thank you to everyone helping make Herdr better.
diff --git a/website/src/data/plugins-fixture.json b/website/src/data/plugins-fixture.json
deleted file mode 100644
index c41ab764..00000000
--- a/website/src/data/plugins-fixture.json
+++ /dev/null
@@ -1,245 +0,0 @@
-{
- "schemaVersion": 1,
- "generatedAt": "2026-06-20T12:00:00.000Z",
- "pluginCount": 10,
- "repositoryCount": 7,
- "source": {
- "provider": "github",
- "query": "topic:herdr-plugin",
- "totalCount": 8,
- "collectedCount": 8,
- "truncated": false
- },
- "plugins": [
- {
- "id": 123456789,
- "fullName": "ogulcancelik/herdr-plugin-github-start",
- "owner": "ogulcancelik",
- "name": "herdr-plugin-github-start",
- "description": "Start Codex or Claude from a GitHub issue, PR, or discussion without leaving the terminal.",
- "url": "https://github.com/ogulcancelik/herdr-plugin-github-start",
- "stars": 42,
- "forks": 3,
- "openIssues": 1,
- "language": "TypeScript",
- "topics": ["herdr-plugin", "github", "agents"],
- "createdAt": "2026-05-01T00:00:00Z",
- "updatedAt": "2026-06-19T19:58:26Z",
- "pushedAt": "2026-06-19T19:58:26Z",
- "archived": false,
- "fork": false,
- "manifests": [
- {
- "path": "herdr-plugin.toml",
- "id": "github-start",
- "name": "GitHub Start",
- "version": "1.4.0",
- "minHerdrVersion": "0.7.0",
- "description": "Start an agent from a GitHub issue, PR, or discussion.",
- "platforms": ["linux", "macos"]
- }
- ]
- },
- {
- "id": 223456789,
- "fullName": "ogulcancelik/herdr-plugin-examples",
- "owner": "ogulcancelik",
- "name": "herdr-plugin-examples",
- "description": "Cookbook of example Herdr plugins: telegram notify, link preview, dev layout bootstrap.",
- "url": "https://github.com/ogulcancelik/herdr-plugin-examples",
- "stars": 28,
- "forks": 6,
- "openIssues": 0,
- "language": "JavaScript",
- "topics": ["herdr-plugin", "examples"],
- "createdAt": "2026-04-12T00:00:00Z",
- "updatedAt": "2026-06-18T08:10:00Z",
- "pushedAt": "2026-06-18T08:10:00Z",
- "archived": false,
- "fork": false,
- "manifests": [
- {
- "path": "agent-telegram-notify/herdr-plugin.toml",
- "id": "agent-telegram-notify",
- "name": "Telegram Notify",
- "version": "0.3.1",
- "minHerdrVersion": "0.7.0",
- "description": "Send a Telegram message when an agent blocks or finishes.",
- "platforms": ["linux", "macos"]
- },
- {
- "path": "link-preview/herdr-plugin.toml",
- "id": "link-preview",
- "name": "Link Preview",
- "version": "0.2.0",
- "minHerdrVersion": "0.7.0",
- "description": "Preview a URL from pane output without leaving the terminal.",
- "platforms": ["linux", "macos"]
- },
- {
- "path": "worktree-bootstrap/herdr-plugin.toml",
- "id": "worktree-bootstrap",
- "name": "Worktree Bootstrap",
- "version": "0.5.0",
- "minHerdrVersion": "0.7.0",
- "description": "Create a worktree, install dependencies, and open a layout in one step.",
- "platforms": ["linux", "macos", "windows"]
- }
- ]
- },
- {
- "id": 323456789,
- "fullName": "lindqvist/herdr-board",
- "owner": "lindqvist",
- "name": "herdr-board",
- "description": "A live project board pane for Herdr that tracks agent tasks across worktrees.",
- "url": "https://github.com/lindqvist/herdr-board",
- "stars": 19,
- "forks": 1,
- "openIssues": 4,
- "language": "Rust",
- "topics": ["herdr-plugin", "pane", "kanban"],
- "createdAt": "2026-05-20T00:00:00Z",
- "updatedAt": "2026-06-17T14:02:00Z",
- "pushedAt": "2026-06-17T14:02:00Z",
- "archived": false,
- "fork": false,
- "manifests": [
- {
- "path": "herdr-plugin.toml",
- "id": "lindqvist.board",
- "name": "Board",
- "version": "2.1.0",
- "minHerdrVersion": "0.7.5",
- "description": "A live project board pane that tracks agent tasks across worktrees.",
- "platforms": ["linux", "macos"]
- }
- ]
- },
- {
- "id": 423456789,
- "fullName": "mira-dev/herdr-layout-presets",
- "owner": "mira-dev",
- "name": "herdr-layout-presets",
- "description": "Apply opinionated split-pane layouts per project with one keybinding.",
- "url": "https://github.com/mira-dev/herdr-layout-presets",
- "stars": 11,
- "forks": 0,
- "openIssues": 2,
- "language": "Lua",
- "topics": ["herdr-plugin", "layout"],
- "createdAt": "2026-06-01T00:00:00Z",
- "updatedAt": "2026-06-15T09:30:00Z",
- "pushedAt": "2026-06-15T09:30:00Z",
- "archived": false,
- "fork": false,
- "manifests": [
- {
- "path": "herdr-plugin.toml",
- "id": "layout-presets",
- "name": "Layout Presets",
- "version": "0.9.2",
- "minHerdrVersion": "0.7.0",
- "description": "Apply opinionated split-pane layouts per project with one keybinding.",
- "platforms": ["linux", "macos"]
- }
- ]
- },
- {
- "id": 523456789,
- "fullName": "okabe/herdr-jira-bridge",
- "owner": "okabe",
- "name": "herdr-jira-bridge",
- "description": "Open Jira tickets as Herdr workspaces and push agent summaries back as comments.",
- "url": "https://github.com/okabe/herdr-jira-bridge",
- "stars": 7,
- "forks": 2,
- "openIssues": 0,
- "language": "Python",
- "topics": ["herdr-plugin", "jira", "integration"],
- "createdAt": "2026-05-28T00:00:00Z",
- "updatedAt": "2026-06-10T11:45:00Z",
- "pushedAt": "2026-06-10T11:45:00Z",
- "archived": false,
- "fork": false,
- "manifests": [
- {
- "path": "plugin/herdr-plugin.toml",
- "id": "jira-bridge",
- "name": "Jira Bridge",
- "version": "0.4.0",
- "minHerdrVersion": "0.7.0",
- "description": "Open Jira tickets as workspaces and push agent summaries back as comments.",
- "platforms": ["linux", "macos"]
- },
- {
- "path": "plugin-cloud/herdr-plugin.toml",
- "id": "jira-bridge-cloud",
- "name": "Jira Bridge Cloud",
- "version": "0.4.0",
- "minHerdrVersion": "0.7.0",
- "description": "The Jira Cloud variant of the bridge.",
- "platforms": ["linux", "macos"]
- }
- ]
- },
- {
- "id": 623456789,
- "fullName": "noor/herdr-notify",
- "owner": "noor",
- "name": "herdr-notify",
- "description": "Desktop and mobile notifications when an agent finishes, blocks, or needs input.",
- "url": "https://github.com/noor/herdr-notify",
- "stars": 4,
- "forks": 0,
- "openIssues": 1,
- "language": "Go",
- "topics": ["herdr-plugin", "notifications"],
- "createdAt": "2026-06-05T00:00:00Z",
- "updatedAt": "2026-06-08T16:20:00Z",
- "pushedAt": "2026-06-08T16:20:00Z",
- "archived": false,
- "fork": false,
- "manifests": [
- {
- "path": "herdr-plugin.toml",
- "id": "notify",
- "name": "Notify",
- "version": "1.0.0",
- "minHerdrVersion": "0.7.0",
- "description": "Desktop and mobile notifications when an agent finishes, blocks, or needs input.",
- "platforms": ["linux", "macos", "windows"]
- }
- ]
- },
- {
- "id": 723456789,
- "fullName": "small-tools/herdr-snippet-runner",
- "owner": "small-tools",
- "name": "herdr-snippet-runner",
- "description": null,
- "url": "https://github.com/small-tools/herdr-snippet-runner",
- "stars": 0,
- "forks": 0,
- "openIssues": 0,
- "language": null,
- "topics": ["herdr-plugin"],
- "createdAt": "2026-06-14T00:00:00Z",
- "updatedAt": "2026-06-14T10:00:00Z",
- "pushedAt": "2026-06-14T10:00:00Z",
- "archived": false,
- "fork": false,
- "manifests": [
- {
- "path": "herdr-plugin.toml",
- "id": "snippet-runner",
- "name": "snippet-runner",
- "version": "0.1.0",
- "minHerdrVersion": "0.7.0",
- "description": null,
- "platforms": ["linux"]
- }
- ]
- }
- ]
-}
diff --git a/website/src/docs-path.test.ts b/website/src/docs-path.test.ts
deleted file mode 100644
index 0fadb26e..00000000
--- a/website/src/docs-path.test.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { describe, expect, test } from 'bun:test';
-import { docsPath, docsRoute, docsTargetHref, docsVersion } from './docs-path';
-
-const scopes = {
- stable: { locales: { root: ['', 'install'], ja: ['', 'install'] } },
- preview: { locales: { root: ['', 'install', 'new-page'], ja: ['', 'install'] } },
- '0.7.4': { locales: { root: ['', 'install'], ja: [''] } },
-};
-
-describe('docsRoute', () => {
- test.each([
- ['/docs/', { isDocs: true, locale: undefined, target: 'stable', page: '' }],
- ['/ja/docs/install/', { isDocs: true, locale: 'ja', target: 'stable', page: 'install' }],
- ['/docs/preview/new-page/', { isDocs: true, locale: undefined, target: 'preview', page: 'new-page' }],
- ['/zh-cn/docs/preview/', { isDocs: true, locale: 'zh-cn', target: 'preview', page: '' }],
- ['/docs/0.7.4/install/', { isDocs: true, locale: undefined, target: '0.7.4', page: 'install' }],
- ['/ja/docs/0.7.4/', { isDocs: true, locale: 'ja', target: '0.7.4', page: '' }],
- ['/blog/', { isDocs: false, locale: undefined, target: 'stable', page: '' }],
- ])('parses %s', (pathname, expected) => {
- expect(docsRoute(pathname)).toEqual(expected);
- });
-});
-
-describe('docsVersion', () => {
- test.each([
- ['/docs/', 'stable'],
- ['/ja/docs/preview/install/', 'preview'],
- ['/zh-cn/docs/0.7.4/', '0.7.4'],
- ])('maps %s', (pathname, version) => {
- expect(docsVersion(pathname)).toBe(version);
- });
-});
-
-describe('docsTargetHref', () => {
- test.each([
- ['/docs/install/', 'preview', '/docs/preview/install/'],
- ['/ja/docs/install/', '0.7.4', '/ja/docs/0.7.4/'],
- ['/docs/0.7.4/install/', 'stable', '/docs/install/'],
- ['/docs/preview/new-page/', '0.7.4', '/docs/0.7.4/'],
- ])('maps %s to %s', (pathname, target, expected) => {
- expect(docsTargetHref(docsRoute(pathname), target, scopes)).toBe(expected);
- });
-});
-
-describe('docsPath', () => {
- test.each([
- ['index.mdx', 'docs'],
- ['install.mdx', 'docs/install'],
- ['ja/index.mdx', 'ja/docs'],
- ['ja/install.mdx', 'ja/docs/install'],
- ['zh-cn/install.mdx', 'zh-cn/docs/install'],
- ['preview/index.mdx', 'docs/preview'],
- ['preview/install.mdx', 'docs/preview/install'],
- ['preview/ja/index.mdx', 'ja/docs/preview'],
- ['preview/ja/install.mdx', 'ja/docs/preview/install'],
- ['_versions/0.7.4/index.mdx', 'docs/0.7.4'],
- ['_versions/0.7.4/install.mdx', 'docs/0.7.4/install'],
- ['_versions/0.7.4/ja/index.mdx', 'ja/docs/0.7.4'],
- ['_versions/0.7.4/zh-cn/install.mdx', 'zh-cn/docs/0.7.4/install'],
- ])('maps %s to %s', (entry, expected) => {
- expect(docsPath({ entry })).toBe(expected);
- });
-});
diff --git a/website/src/docs-path.ts b/website/src/docs-path.ts
deleted file mode 100644
index 53ace41d..00000000
--- a/website/src/docs-path.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-const docsLocales = new Set(['ja', 'zh-cn']);
-const docsVersionPattern = /^\d+\.\d+\.\d+$/;
-
-export type DocsTarget = 'stable' | 'preview' | string;
-
-export interface DocsRoute {
- isDocs: boolean;
- locale: string | undefined;
- target: DocsTarget;
- page: string;
-}
-
-export interface DocsScope {
- locales: Record<string, string[]>;
-}
-
-export function docsRoute(pathname: string): DocsRoute {
- const segments = pathname.split('/').filter(Boolean);
- let locale: string | undefined;
-
- if (segments[0] && docsLocales.has(segments[0])) {
- locale = segments.shift();
- }
-
- if (segments.shift() !== 'docs') {
- return { isDocs: false, locale, target: 'stable', page: '' };
- }
-
- let target: DocsTarget = 'stable';
- if (segments[0] === 'preview') {
- target = 'preview';
- segments.shift();
- } else if (segments[0] && docsVersionPattern.test(segments[0])) {
- target = segments.shift()!;
- }
-
- return {
- isDocs: true,
- locale,
- target,
- page: segments.join('/'),
- };
-}
-
-export function docsVersion(pathname: string) {
- return docsRoute(pathname).target;
-}
-
-export function docsTargetHref(
- route: DocsRoute,
- target: DocsTarget,
- scopes?: Record<string, DocsScope>,
-) {
- if (!route.isDocs) throw new Error('cannot build a documentation target from a non-docs route');
-
- const localeKey = route.locale ?? 'root';
- const availablePages = scopes?.[target]?.locales[localeKey];
- const page = availablePages?.includes(route.page) === false ? '' : route.page;
- const prefix = route.locale ? `/${route.locale}` : '';
- const targetSegment = target === 'stable' ? '' : `/${target}`;
- return `${prefix}/docs${targetSegment}${page ? `/${page}` : ''}/`;
-}
-
-export function docsPath({ entry }: { entry: string }) {
- const slug = entry.replace(/\.(md|mdx|markdown|mdown|mkdn|mkd|mdwn)$/i, '');
- const normalized = slug.replace(/\/index$/, '');
- const segments = normalized.split('/');
-
- let targetSegment = '';
- if (segments[0] === 'preview') {
- targetSegment = 'preview';
- segments.shift();
- } else if (segments[0] === '_versions' && segments[1] && docsVersionPattern.test(segments[1])) {
- segments.shift();
- targetSegment = segments.shift()!;
- }
-
- let locale: string | undefined;
- if (segments[0] && docsLocales.has(segments[0])) {
- locale = segments.shift();
- }
-
- const page = segments.join('/');
- const prefix = locale ? `${locale}/` : '';
- const target = targetSegment ? `/${targetSegment}` : '';
- return `${prefix}docs${target}${page && page !== 'index' ? `/${page}` : ''}`;
-}
diff --git a/website/src/pages/blog/[slug].astro b/website/src/pages/blog/[slug].astro
deleted file mode 100644
index 3c33a38c..00000000
--- a/website/src/pages/blog/[slug].astro
+++ /dev/null
@@ -1,95 +0,0 @@
----
-import { getCollection, render } from 'astro:content';
-import SiteLayout from '../../components/SiteLayout.astro';
-import AuthorCard from '../../components/AuthorCard.astro';
-
-export async function getStaticPaths() {
- const posts = await getCollection('blog');
- /* dev only, see blog/index.astro */
- return posts
- .filter((post) => import.meta.env.DEV || !post.data.draft)
- .map((post) => {
- const slug = post.id.replace(/\.(md|mdx)$/i, '');
- return { params: { slug }, props: { post, slug } };
- });
-}
-
-const { post, slug } = Astro.props;
-const { Content, headings } = await render(post);
-const sectionHeadings = headings.filter((heading) => heading.depth === 2);
----
-
-<SiteLayout
- title={`${post.data.title} — Herdr blog`}
- description={post.data.description}
- canonicalPath={`/blog/${slug}/`}
- ogType="article"
- ogImage={post.data.ogImage}
- ogImageAlt={post.data.ogImage ? post.data.title : undefined}
->
- {/* a post with no h2s renders no sidebar, so the grid must stop reserving
- a column for it */}
- <div class:list={['article', sectionHeadings.length === 0 && 'article-solo']}>
- <article class="article-body">
- <p class="article-meta">
- <a href="/blog/">← Blog</a>
- <time datetime={post.data.date.toISOString()}>
- {post.data.date.toLocaleDateString('en', {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- })}
- </time>
- </p>
- <h1>{post.data.title}</h1>
- {post.data.lede && post.data.description && (
- <p class="article-lede">{post.data.description}</p>
- )}
- <hr class="article-rule" />
- <div class="prose">
- <Content />
- </div>
- <AuthorCard />
- </article>
-
- {sectionHeadings.length > 0 && (
- <aside class="toc" aria-label="Article sections">
- <p>Sections</p>
- <nav>
- {sectionHeadings.map((heading) => (
- <a href={`#${heading.slug}`} data-heading-link={heading.slug}>{heading.text}</a>
- ))}
- </nav>
- </aside>
- )}
- </div>
-
- <script>
- const headings = Array.from(document.querySelectorAll('.prose h2[id]'));
- const links = new Map(
- Array.from(document.querySelectorAll('[data-heading-link]')).map((link) => [
- link.getAttribute('data-heading-link'),
- link,
- ]),
- );
-
- function setActive(id) {
- for (const link of links.values()) link.removeAttribute('aria-current');
- links.get(id)?.setAttribute('aria-current', 'true');
- }
-
- if (headings.length > 0 && links.size > 0) {
- setActive(headings[0].id);
- const observer = new IntersectionObserver(
- (entries) => {
- const visible = entries
- .filter((entry) => entry.isIntersecting)
- .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];
- if (visible?.target instanceof HTMLElement) setActive(visible.target.id);
- },
- { rootMargin: '-18% 0px -68% 0px', threshold: 0 },
- );
- for (const heading of headings) observer.observe(heading);
- }
- </script>
-</SiteLayout>
diff --git a/website/src/pages/blog/index.astro b/website/src/pages/blog/index.astro
deleted file mode 100644
index de9349ea..00000000
--- a/website/src/pages/blog/index.astro
+++ /dev/null
@@ -1,42 +0,0 @@
----
-import { getCollection } from 'astro:content';
-import SiteLayout from '../../components/SiteLayout.astro';
-
-/* Drafts render locally and never in a build, so an unpublished post can be
- reviewed on the dev server without being one deploy away from going live. */
-const posts = (await getCollection('blog'))
- .filter((post) => import.meta.env.DEV || !post.data.draft)
- .map((post) => ({ ...post, slug: post.id.replace(/\.(md|mdx)$/i, '') }))
- .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
-
-const stamp = (date) =>
- date.toLocaleDateString('en', { year: 'numeric', month: 'short', day: 'numeric' });
----
-
-<SiteLayout
- title="Herdr blog"
- description="Notes on the agent runtime — product decisions, implementation writeups, and what we learned running agents on machines nobody is watching."
- canonicalPath="/blog/"
->
- <header class="ph">
- <div class="hd-eyebrow"><s></s>the blog</div>
- <h1>Notes from the herd.</h1>
- <p>
- Product decisions, implementation writeups, and what we learn running agents on
- machines nobody is watching.
- </p>
- </header>
-
- <div class="posts">
- {posts.map((post) => (
- <a href={`/blog/${post.slug}/`}>
- <time datetime={post.data.date.toISOString()}>{stamp(post.data.date)}</time>
- <div>
- <h2>{post.data.title}</h2>
- {post.data.description && <p>{post.data.description}</p>}
- </div>
- <span class="go-arrow" aria-hidden="true">→</span>
- </a>
- ))}
- </div>
-</SiteLayout>
diff --git a/website/src/pages/compare.astro b/website/src/pages/compare.astro
deleted file mode 100644
index 315d6a1b..00000000
--- a/website/src/pages/compare.astro
+++ /dev/null
@@ -1,265 +0,0 @@
----
-import SiteLayout from '../components/SiteLayout.astro';
----
-
-<SiteLayout
- title="Compare Herdr vs tmux, Zellij, cmux, Warp & agent managers"
- description="Compare Herdr with tmux, Zellij, cmux, Warp, Solo, Conductor, Emdash, and Superset. Multiplexers persist terminals and apps manage agents. Herdr is the runtime agents live on, with clients on top."
- canonicalPath="/compare/"
->
- <main>
- <header class="ph ph-split">
- <div>
- <div class="hd-eyebrow"><s></s>compare</div>
- <h1>Apps manage the herd. Herdr <em>runs</em> it.</h1>
- <p>
- Most tools Herdr gets compared to are apps: a window you open to
- manage coding agents, and a window the work depends on. Herdr is a
- different kind of thing: a runtime. A server holds real terminals
- open on the machine, the agents live in those, and every UI, ours
- included, is just a client that attaches. Keep that split in mind
- and the matrix below mostly explains itself.
- </p>
- </div>
- <aside class="ph-side">
- <b>9</b>
- <span>tools compared · one runtime</span>
- </aside>
- </header>
-
- <section class="cmp" id="matrix">
- <div class="fighd">
- <span>herdr against the field</span>
- <span class="r">scrolls sideways on a phone</span>
- </div>
- <div class="cmp-scroll">
- <table>
- <thead>
- <tr>
- <th>capability</th>
- <th class="h">herdr</th>
- <th>tmux · zellij</th>
- <th>cmux · warp</th>
- <th>solo</th>
- <th>conductor · emdash · superset</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th scope="row">Kind of thing</th>
- <td class="h">runtime + clients</td>
- <td>terminal multiplexer</td>
- <td>terminal app</td>
- <td>process dashboard</td>
- <td>manager app</td>
- </tr>
- <tr>
- <th scope="row">Work survives its own UI closing</th>
- <td class="h">yes, the server owns the terminals</td>
- <td>yes, detach</td>
- <td>session restore</td>
- <td>while the app is open</td>
- <td>while the app is open</td>
- </tr>
- <tr>
- <th scope="row">Runs inside your existing terminal</th>
- <td class="h">yes</td>
- <td>yes</td>
- <td>replaces it</td>
- <td class="no">no, desktop app</td>
- <td class="no">no, desktop app</td>
- </tr>
- <tr>
- <th scope="row">Semantic agent state</th>
- <td class="h">blocked · working · done · idle</td>
- <td class="no">—</td>
- <td>attention cues</td>
- <td>process status</td>
- <td>workspace status</td>
- </tr>
- <tr>
- <th scope="row">Detach, reattach, SSH in</th>
- <td class="h">yes, any tty</td>
- <td>yes</td>
- <td>partial</td>
- <td class="no">—</td>
- <td>remote projects</td>
- </tr>
- <tr>
- <th scope="row">Direct attach to one agent</th>
- <td class="h">yes</td>
- <td class="no">—</td>
- <td class="no">—</td>
- <td class="no">—</td>
- <td class="no">—</td>
- </tr>
- <tr>
- <th scope="row">API agents drive themselves</th>
- <td class="h">read · send · wait · split · attach</td>
- <td>terminal scripting</td>
- <td>app APIs</td>
- <td>MCP for processes</td>
- <td>workflow APIs</td>
- </tr>
- <tr>
- <th scope="row">Worktree and diff review flow</th>
- <td class="h">pairs with it</td>
- <td class="no">—</td>
- <td>partial</td>
- <td class="no">—</td>
- <td>yes, their core</td>
- </tr>
- <tr>
- <th scope="row">Clients on the same runtime</th>
- <td class="h">TUI · CLI · plain SSH, more coming</td>
- <td>its own client</td>
- <td>the app only</td>
- <td>the app only</td>
- <td>the app only</td>
- </tr>
- </tbody>
- </table>
- </div>
- <p class="figcap">
- The columns are categories, not enemies: Herdr pairs happily with a
- worktree manager and runs fine inside a fancy terminal.
- <b>The row that sorts the field is the second one:</b> what happens to
- the agents when the thing you're looking at goes away.
- </p>
- </section>
-
- <div class="caps">
- <div class="cap cap-flat">
- <div class="n"><span>01</span></div>
- <div class="cap-in">
- <h3>Herdr is the runtime.</h3>
- <p>
- A server owns the terminals; every UI is a client of it. The TUI in
- the screenshots attaches, detaches and even crashes without the
- agents noticing. Same for the CLI, plain SSH, and whatever
- attaches next. The TUI is the first client, not the last.
- </p>
- </div>
- <div class="ev" aria-hidden="true">
- <div class="ev-row"><span>herdr-server</span><b><i class="beat"></i>up</b></div>
- <div class="ev-note">4 agents · 0 clients attached · still working</div>
- </div>
- </div>
- <div class="cap cap-flat">
- <div class="n"><span>02</span></div>
- <div class="cap-in">
- <h3>Multiplexers persist terminals, not agents.</h3>
- <p>
- tmux gave humans persistence, and Herdr keeps that whole
- inheritance: real PTYs, detach, SSH. What it adds is the part
- multiplexers never had: knowing which pane is an agent, whether
- it's blocked, and how to wait on it instead of polling it.
- </p>
- </div>
- <div class="ev" aria-hidden="true">
- <div class="ev-row"><span>tmux ls</span><b>3 sessions</b></div>
- <div class="ev-note">which one is waiting on you? no idea</div>
- </div>
- </div>
- <div class="cap cap-flat">
- <div class="n"><span>03</span></div>
- <div class="cap-in">
- <h3>Terminal apps replace your terminal.</h3>
- <p>
- cmux and Warp can be genuinely polished, but the deal is that the
- work moves into their window, with their renderer, on the machines
- they support. Herdr changes nothing about your terminal. It runs
- inside it, wherever a terminal and SSH already reach.
- </p>
- </div>
- <div class="ev" aria-hidden="true">
- <div class="ev-row"><span>ghostty · kitty · iterm · alacritty</span><b>kept</b></div>
- <div class="ev-note">herdr runs in the one you already chose</div>
- </div>
- </div>
- <div class="cap cap-flat">
- <div class="n"><span>04</span></div>
- <div class="cap-in">
- <h3>Manager apps are clients without a runtime.</h3>
- <p>
- Conductor, Emdash and Superset manage a herd from a window:
- worktrees, diffs, review queues. Useful, and Herdr pairs fine with
- that flow. But a window that manages agents is not a place agents
- live: quit the app and the herd goes with it.
- </p>
- </div>
- <div class="ev" aria-hidden="true">
- <div class="ev-row"><span>their app quits</span><b>agents stop</b></div>
- <div class="ev-row"><span>every herdr client quits</span><b>agents keep going</b></div>
- </div>
- </div>
- <div class="cap cap-flat">
- <div class="n"><span>05</span></div>
- <div class="cap-in">
- <h3>Dashboards watch processes.</h3>
- <p>
- Solo supervises a dev stack: health, restarts, logs. Herdr's job
- is different: interactive agent terminals that stay open, hold
- scrollback and state, and stay yours whether or not anything is
- watching them.
- </p>
- </div>
- <div class="ev" aria-hidden="true">
- <div class="ev-row"><span>process status</span><b>up / down</b></div>
- <div class="ev-row"><span>agent state</span><b>blocked · working · idle</b></div>
- </div>
- </div>
- </div>
-
- <section class="vs">
- <div class="fighd">
- <span>one-liners, for deciding fast</span>
- </div>
- <div class="vs-list">
- <article>
- <b>herdr vs tmux</b>
- <p>tmux keeps terminals alive; so does Herdr. The difference is Herdr knows which terminals are agents, what state each one is in, and how to wait on them. tmux sees panes.</p>
- </article>
- <article>
- <b>herdr vs zellij</b>
- <p>Zellij is a friendlier workspace for humans in terminals. Herdr is a runtime for agents in terminals: state, waits, direct attach, and an API.</p>
- </article>
- <article>
- <b>herdr vs cmux</b>
- <p>cmux is a Mac terminal app built around agents. Herdr isn't an app: it's the runtime underneath, in whatever terminal you already use, reachable over SSH.</p>
- </article>
- <article>
- <b>herdr vs warp</b>
- <p>Warp wants to be your terminal and your platform. Herdr keeps your terminal and owns what runs inside it.</p>
- </article>
- <article>
- <b>herdr vs opencode web</b>
- <p>opencode's web mode serves one agent over HTTP. Herdr runs the whole herd: any agent CLI, many at once, from any tty.</p>
- </article>
- <article>
- <b>herdr vs solo</b>
- <p>Solo is a dashboard that supervises your dev processes. Herdr holds interactive agent terminals open whether or not anything is watching them.</p>
- </article>
- <article>
- <b>herdr vs conductor, emdash, superset</b>
- <p>Manager apps put worktrees, diffs and review queues in a window. Herdr is the layer under that kind of window: quit their app and the agents stop; detach every Herdr client and they don't.</p>
- </article>
- </div>
- </section>
-
- <section class="end">
- <span class="ram"></span>
- <div class="in">
- <h2>A runtime, not another window.</h2>
- <p>
- Install it and nothing about your setup changes: same terminal, same
- agent CLIs. They just stop dying when a window does.
- </p>
- <div class="ph-actions">
- <a class="btn-solid" href="/docs/install/">Install Herdr</a>
- <a class="btn-ghost" href="/docs/quick-start/">Quick start</a>
- </div>
- </div>
- </section>
- </main>
-</SiteLayout>
diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro
deleted file mode 100644
index 26a048d4..00000000
--- a/website/src/pages/index.astro
+++ /dev/null
@@ -1,33 +0,0 @@
----
-import { readFile } from 'node:fs/promises';
-import { agentCount, fmt, releaseVersion, siteStats } from '../site-data';
-
-/* The numbers in the nav and hero strip are baked here at build time from the
- snapshots and latest.json, so the page ships with real values, renders
- correctly without JS, and can never be more than one deploy stale. A small
- script on the page refreshes the counts live afterwards. */
-const homepage = await readFile(new URL('../../index.html', import.meta.url), 'utf8');
-
-const { starCount, installCount, pluginCount } = await siteStats();
-const version = await releaseVersion();
-const facts = version ? `v${version} · Apache 2.0` : 'Apache 2.0';
-
-/* the line drops out entirely rather than showing a placeholder if the
- manifests can't be read — a missing sentence beats a wrong number */
-const agents = await agentCount();
-const agentsNote = agents ? `${agents} agents detected out of the box` : '';
-/* the strip carried a hardcoded 19; same source as row 04 now */
-const agentsCount = agents ? String(agents) : '—';
-
-/* replaceAll, not replace: the star count appears in the nav as well as the
- strip, and replace() would fill only the first of them. */
-const page = homepage
- .replaceAll('<!--N_STARS-->', fmt(starCount))
- .replaceAll('<!--N_INSTALLS-->', fmt(installCount))
- .replaceAll('<!--N_PLUGINS-->', fmt(pluginCount))
- .replaceAll('<!--FACTS-->', facts)
- .replaceAll('<!--AGENTS_NOTE-->', agentsNote)
- .replaceAll('<!--N_AGENTS-->', agentsCount);
----
-
-<Fragment set:html={page} />
diff --git a/website/src/pages/og/card-b.html b/website/src/pages/og/card-b.html
deleted file mode 100644
index c508778b..00000000
--- a/website/src/pages/og/card-b.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!doctype html>
-<html lang="en" class="og">
-<head>
-<meta charset="utf-8" />
-<meta name="viewport" content="width=device-width, initial-scale=1" />
-<title>herdr OG card — source</title>
-<meta name="robots" content="noindex" />
-<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&display=swap" rel="stylesheet" />
-<link rel="stylesheet" href="/css/og-card.css?v=3" />
-<style>
- /* Source of truth for /assets/og-card-v9.png.
- Regenerate: open this page, capture the full document, crop to the
- leftmost 1200x630 (the document is pinned to exactly the card size, but
- the browser viewport may be wider). Bump the filename when the artwork
- changes — Slack, X and LinkedIn cache unfurls by URL for weeks. */
- /* centre the headline in the band below the head rather than in the whole
- card, so a four-line headline can't ride up into the lockup */
- .in { display: flex; flex-direction: column; justify-content: center; padding-top: 118px; }
- h1 {
- font-family: var(--disp);
- font-weight: 900;
- letter-spacing: -0.055em;
- line-height: 0.86;
- font-size: 104px;
- margin: 30px 0 0;
- max-width: 15ch;
- color: var(--ink);
- }
- h1 em { font-style: normal; color: var(--spot); }
- /* X, LinkedIn and Slack all draw their own attribution over the bottom of an
- unfurl, so the lockup and provenance sit at the top and the bottom band is
- left deliberately empty. */
- .head {
- position: absolute;
- left: 62px;
- right: 62px;
- top: 48px;
- z-index: 1;
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .head .sub { color: var(--faint); font-size: 21px; letter-spacing: 0.1em; }
- .head .sub b { color: var(--dim); font-weight: 400; }
-</style>
-</head>
-<body class="og">
-<div class="card">
- <span class="ram mass"></span>
- <div class="head">
- <div class="lockup"><span class="ram"></span><b>herdr</b></div>
- <div class="sub"><b>herdr.dev</b> &nbsp;·&nbsp; Apache 2.0</div>
- </div>
- <div class="in pad">
- <div class="eyebrow"><s></s>the agent runtime</div>
- <h1>Run them <em>anywhere.</em> Leave them running.</h1>
- </div>
-</div>
-</body>
-</html>
diff --git a/website/src/pages/og/card-perf.html b/website/src/pages/og/card-perf.html
deleted file mode 100644
index e2142252..00000000
--- a/website/src/pages/og/card-perf.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!doctype html>
-<html lang="en" class="og">
-<head>
-<meta charset="utf-8" />
-<meta name="viewport" content="width=device-width, initial-scale=1" />
-<title>herdr performance OG card — source</title>
-<meta name="robots" content="noindex" />
-<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&display=swap" rel="stylesheet" />
-<link rel="stylesheet" href="/css/og-card.css?v=3" />
-<style>
- /* Source of truth for /assets/og-blog-frames-v1.png. Same capture recipe as
- card-b: open the page, capture the full document, it is already 1200x630.
-
- A share card is read at thumbnail size in a timeline, so it carries the
- headline and the one measurement that backs it. The caveats live in the
- post, where there is room to read them. */
- .head {
- position: absolute; left: 62px; right: 62px; top: 48px; z-index: 1;
- display: flex; align-items: center; justify-content: space-between;
- }
- .head .sub { color: var(--faint); font-size: 21px; letter-spacing: 0.1em; }
- .head .sub b { color: var(--dim); font-weight: 400; }
-
- .in { display: flex; flex-direction: column; justify-content: center; padding: 118px 62px 54px; }
- h1 {
- font-family: var(--disp); font-weight: 900; letter-spacing: -0.055em;
- line-height: 0.9; font-size: 96px; margin: 0; color: var(--ink);
- }
- h1 em { font-style: normal; color: var(--spot); }
-
- .meas {
- display: flex; align-items: baseline; gap: 22px;
- margin-top: 42px; padding-top: 22px; border-top: 1px solid var(--line2);
- color: var(--faint); font-size: 22px; letter-spacing: 0.04em;
- }
- .meas b { color: var(--ink); font-weight: 400; }
- .meas .r { margin-left: auto; color: var(--dim); }
-</style>
-</head>
-<body class="og">
-<div class="card">
- <span class="ram mass"></span>
- <div class="head">
- <div class="lockup"><span class="ram"></span><b>herdr</b></div>
- <div class="sub"><b>herdr.dev</b> &nbsp;·&nbsp; Apache 2.0</div>
- </div>
- <div class="in">
- <h1>Ten agents,<br />three clients,<br /><em>95% less CPU.</em></h1>
- <div class="meas">
- <span>total cpu <b>13.014% → 0.617%</b></span>
- <span class="r">v0.7.5 → v0.8.0</span>
- </div>
- </div>
-</div>
-</body>
-</html>
diff --git a/website/src/pages/og/card-yc.html b/website/src/pages/og/card-yc.html
deleted file mode 100644
index af8c69e7..00000000
--- a/website/src/pages/og/card-yc.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!doctype html>
-<html lang="en" class="og">
-<head>
-<meta charset="utf-8" />
-<meta name="viewport" content="width=device-width, initial-scale=1" />
-<title>herdr YC announcement OG card — source</title>
-<meta name="robots" content="noindex" />
-<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&display=swap" rel="stylesheet" />
-<link rel="stylesheet" href="/css/og-card.css?v=3" />
-<style>
- /* Source of truth for /assets/og-blog-yc-v1.png. Same capture recipe as
- card-b: open the page, capture the full document, it is already 1200x630. */
- :root { --spot: #fb651e; } /* YC orange, this card only */
- .head {
- position: absolute; left: 62px; right: 62px; top: 48px; z-index: 1;
- display: flex; align-items: center; justify-content: space-between;
- }
- .head .sub { color: var(--faint); font-size: 21px; letter-spacing: 0.1em; }
- .head .sub b { color: var(--dim); font-weight: 400; }
-
- .in { display: flex; flex-direction: column; justify-content: center; padding: 118px 62px 54px; }
- /* headline is the post title verbatim */
- h1 {
- font-family: var(--disp); font-weight: 900; letter-spacing: -0.055em;
- line-height: 0.9; font-size: 92px; margin: 0; color: var(--ink);
- }
- h1 em { font-style: normal; color: var(--spot); }
-</style>
-</head>
-<body class="og">
-<div class="card">
- <span class="ram mass"></span>
- <div class="head">
- <div class="lockup"><span class="ram"></span><b>herdr</b></div>
- <div class="sub"><b>herdr.dev</b> &nbsp;·&nbsp; Apache 2.0</div>
- </div>
- <div class="in">
- <h1>Herdr is joining<br /><em>Y Combinator.</em><br />The runtime stays open.</h1>
- </div>
-</div>
-</body>
-</html>
diff --git a/website/src/pages/plugins.astro b/website/src/pages/plugins.astro
deleted file mode 100644
index 57b189ea..00000000
--- a/website/src/pages/plugins.astro
+++ /dev/null
@@ -1,1159 +0,0 @@
----
-import SiteLayout from '../components/SiteLayout.astro';
-import fixture from '../data/plugins-fixture.json';
-const snapshotUrl = 'https://assets.herdr.dev/plugins/index.json';
-
-// Seed the page server-side from the public R2 snapshot so `bun run dev` and
-// the production build both render real data immediately. If the live fetch
-// fails, dev falls back to a local fixture for offline design; production seeds
-// empty and lets the client fetch fill it (never fake data).
-let liveData = null;
-try {
- const res = await fetch(snapshotUrl);
- if (res.ok) liveData = await res.json();
-} catch {
- // ignore: handled by the fallbacks below
-}
-const initialData = liveData ?? (import.meta.env.DEV ? fixture : null);
-const initialIsFixture = !liveData && import.meta.env.DEV;
-// A card is a repository; a plugin is a validated manifest inside it. A monorepo
-// with three manifests is one card and three plugins, so the two counts differ
-// and both are stated. `source.totalCount` is the raw GitHub topic search and
-// still includes blacklisted and manifest-less repositories, so it is not used.
-const repos = initialData?.plugins ?? [];
-const repositoryCount = initialData?.repositoryCount ?? repos.length;
-const pluginCount =
- initialData?.pluginCount ??
- repos.reduce((n, repo) => n + (repo.manifests?.length || 1), 0);
-const apiUrl = import.meta.env.DEV ? null : snapshotUrl;
----
-
-<SiteLayout
- title="Herdr plugins: community plugin marketplace"
- description="Discover community Herdr plugins published on GitHub. An automatic index of public repositories tagged with the herdr-plugin topic."
- canonicalPath="/plugins/"
->
- <main class="plugins-page">
- <header class="ph ph-split">
- <div>
- <div class="hd-eyebrow"><s></s>the marketplace</div>
- <h1>Built by the herd.</h1>
- <p>
- Community plugins published on GitHub, discovered automatically from the
- <code>herdr-plugin</code> topic. Install any of them with
- <code>herdr plugin install</code>, or publish your own and get listed.
- </p>
- <p class="plugins-trust">
- <span class="status-dot dot-idle"></span>
- Listings aren't reviewed by Herdr, so install at your own discretion.
- <a href="/docs/plugins/#trust-and-security">Trust guidance →</a>
- </p>
- </div>
- <aside class="ph-side">
- <b id="plugins-hero-count">{pluginCount.toLocaleString('en-US')}</b>
- <span id="plugins-hero-summary">
- plugins across {repositoryCount.toLocaleString('en-US')} repositories
- </span>
- <a href="/docs/plugins/">Publish yours →</a>
- </aside>
- </header>
-
- <div id="plugins-shelves" hidden>
- <section class="section plugins-shelf" id="shelf-trending" hidden>
- <div class="shelf-head">
- <div>
- <h2 class="shelf-title">Trending this week</h2>
- <p class="shelf-sub">fastest-growing repositories, relative to their own size</p>
- </div>
- <button class="shelf-all" type="button" data-sort="trending">see all →</button>
- </div>
- <div id="trend-grid" class="trend-grid" role="list"></div>
- </section>
-
- <section class="section plugins-shelf" id="shelf-new" hidden>
- <div class="shelf-head">
- <div>
- <h2 class="shelf-title">New to the herd</h2>
- <p class="shelf-sub">fresh projects that joined recently</p>
- </div>
- <button class="shelf-all" type="button" data-sort="newest">see all →</button>
- </div>
- <div class="new-rows" role="list"></div>
- </section>
- </div>
-
- <section class="section plugins-results">
- <div class="shelf-head plugins-browse-head" id="plugins-browse-head">
- <div>
- <h2 class="shelf-title">Browse everything</h2>
- <p class="shelf-sub">the full index — search or pick a sort</p>
- </div>
- </div>
- <div class="plugins-controls">
- <div class="plugins-search-wrap">
- <span class="plugins-search-icon" aria-hidden="true">/</span>
- <input
- id="plugins-search"
- type="search"
- class="plugins-search"
- placeholder="search plugins, repositories, owners, languages…"
- autocomplete="off"
- spellcheck="false"
- aria-label="Search plugins"
- />
- </div>
- <label class="plugins-sort-wrap">
- <span class="plugins-sort-label">sort</span>
- <select id="plugins-sort" class="plugins-sort" aria-label="Sort plugins">
- <option value="popular">Popular</option>
- <option value="trending">Trending</option>
- <option value="recent">Recently updated</option>
- <option value="newest">Newest</option>
- <option value="name">Name</option>
- </select>
- </label>
- </div>
- <p id="plugins-meta" class="plugins-meta" aria-live="polite"></p>
- <div id="plugins-grid" class="plugins-grid" role="list"></div>
- <div id="plugins-status" class="plugins-status">Loading plugins…</div>
- <button id="plugins-more" class="button button-secondary plugins-more" hidden></button>
- </section>
-
- <section class="section plugins-publish">
- <div class="plugins-publish-card">
- <p class="section-kicker"># publish</p>
- <h3>Want your plugin listed?</h3>
- <p>
- Add the GitHub topic <code>herdr-plugin</code> to a public repository
- with a <code>herdr-plugin.toml</code> manifest. The index picks it up
- on the next refresh. No submission, no review queue.
- </p>
- <div class="plugins-publish-actions">
- <a class="button button-primary" href="/docs/marketplace/">How publishing works</a>
- <a class="button button-secondary" href="/docs/plugins/">Author a plugin</a>
- </div>
- </div>
- </section>
- </main>
-
- <script define:vars={{ initialData, initialIsFixture, apiUrl }}>
- const grid = document.getElementById("plugins-grid");
- const statusEl = document.getElementById("plugins-status");
- const searchInput = document.getElementById("plugins-search");
- const sortSelect = document.getElementById("plugins-sort");
- const metaEl = document.getElementById("plugins-meta");
- const moreButton = document.getElementById("plugins-more");
- const heroCountEl = document.getElementById("plugins-hero-count");
- const heroSummaryEl = document.getElementById("plugins-hero-summary");
- const shelvesWrap = document.getElementById("plugins-shelves");
- const trendingShelf = document.getElementById("shelf-trending");
- const trendGrid = document.getElementById("trend-grid");
- const newShelf = document.getElementById("shelf-new");
-
- // 24 fills complete rows in both the 3-column and 2-column grid layouts.
- const PAGE_SIZE = 24;
- let visibleLimit = PAGE_SIZE;
-
- // A shelf earns its place: percent growth only counts once a repository
- // gained real stars this week, so the long tail (median: 1 star) can't
- // flood trending with 1-to-3-star noise, while big repositories must grow
- // at their own scale to appear.
- const TRENDING_MIN_GAIN = 10;
- // "New" means new to everyone: recently indexed AND a recently created
- // repository. Established projects that just adopted the topic surface
- // through trending instead of burying actual newcomers.
- const NEW_SEEN_MAX_DAYS = 14;
- const NEW_CREATED_MAX_DAYS = 60;
- // Six cards fill complete shelf rows in the 3, 2, and 1 column layouts.
- const SHELF_SIZE = 6;
- // A shelf with one or two cards reads as a struggling marketplace, which
- // is worse than no shelf at all.
- const SHELF_MIN_CARDS = 3;
-
- const LANG_COLORS = {
- TypeScript: "#3178c6",
- JavaScript: "#f1e05a",
- Rust: "#dea584",
- Python: "#3572A5",
- Go: "#00ADD8",
- Lua: "#000080",
- Shell: "#89e051",
- "C++": "#f34b7d",
- Ruby: "#701516",
- };
-
- // One entry per repository. Its `manifests` are the plugins it ships.
- let repos = [];
- let usingFallback = false;
-
- function timeAgo(iso) {
- if (!iso) return null;
- const then = new Date(iso).getTime();
- if (Number.isNaN(then)) return null;
- const secs = Math.max(0, Math.round((Date.now() - then) / 1000));
- const units = [
- ["y", 31536000],
- ["mo", 2592000],
- ["w", 604800],
- ["d", 86400],
- ["h", 3600],
- ["m", 60],
- ];
- for (const [label, size] of units) {
- const v = Math.floor(secs / size);
- if (v >= 1) return v + label + " ago";
- }
- return "just now";
- }
-
- function isGithubUrl(url) {
- return typeof url === "string" && /^https:\/\/github\.com\/[^/]+\/[^/]+/.test(url);
- }
-
- function daysSince(iso) {
- if (!iso) return null;
- const then = new Date(iso).getTime();
- if (Number.isNaN(then)) return null;
- return (Date.now() - then) / 86400000;
- }
-
- function trendingScore(p) {
- const delta = p.starsDelta7d;
- if (typeof delta !== "number" || delta < TRENDING_MIN_GAIN) return null;
- return delta / Math.max((p.stars ?? 0) - delta, 1);
- }
-
- function isNewToHerd(p) {
- const seen = daysSince(p.firstSeenAt);
- const created = daysSince(p.createdAt);
- return (
- seen !== null && seen <= NEW_SEEN_MAX_DAYS &&
- created !== null && created <= NEW_CREATED_MAX_DAYS
- );
- }
-
- function trendingBadge(p) {
- const delta = p.starsDelta7d ?? 0;
- const base = Math.max((p.stars ?? 0) - delta, 0);
- return "▲ " + base + " → " + (p.stars ?? 0) + " ★ this week";
- }
-
- function joinedBadge(p) {
- const ago = timeAgo(p.firstSeenAt);
- return ago === "just now" ? "✦ just joined" : ago ? "✦ joined " + ago : null;
- }
-
- function avatar(p, size) {
- const img = el("img", "plugin-avatar");
- img.src = "https://github.com/" + encodeURIComponent(p.owner || "") + ".png?size=" + size;
- img.alt = "";
- img.loading = "lazy";
- img.width = size / 2;
- img.height = size / 2;
- return img;
- }
-
- function cardShell(p, className) {
- const url = isGithubUrl(p.url) ? p.url : null;
- const card = el(url ? "a" : "div", className);
- card.setAttribute("role", "listitem");
- if (url) {
- card.href = url;
- card.target = "_blank";
- card.rel = "noopener noreferrer";
- }
- return card;
- }
-
- function titleOf(p) {
- const title = el("div", "plugin-title");
- title.appendChild(el("span", "plugin-owner", (p.owner || "?") + "/"));
- title.appendChild(el("span", "plugin-name", p.name || "unknown"));
- return title;
- }
-
- function buildTrendCard(p) {
- const card = cardShell(p, "plugin-card plugin-trend-card");
- const head = el("div", "plugin-card-head");
- const lead = el("div", "trend-lead");
- lead.appendChild(avatar(p, 64));
- lead.appendChild(titleOf(p));
- head.appendChild(lead);
- head.appendChild(el("span", "plugin-go", "↗"));
- card.appendChild(head);
- card.appendChild(el("div", "plugin-badge", trendingBadge(p)));
- const desc = el(
- "p",
- "plugin-desc" + (p.description ? "" : " is-empty"),
- p.description || "No description provided.",
- );
- card.appendChild(desc);
- return card;
- }
-
- function buildRow(p, note) {
- const row = cardShell(p, "plugin-row");
- row.appendChild(avatar(p, 64));
- const body = el("div", "plugin-row-body");
- body.appendChild(titleOf(p));
- const desc = el(
- "span",
- "plugin-row-desc" + (p.description ? "" : " is-empty"),
- p.description || "No description provided.",
- );
- body.appendChild(desc);
- row.appendChild(body);
- const side = el("div", "plugin-row-side");
- if (note) side.appendChild(el("span", "plugin-row-note", note));
- const stars = el("span", "plugin-stat");
- stars.appendChild(el("span", "plugin-star", "★"));
- stars.appendChild(el("span", null, String(p.stars ?? 0)));
- side.appendChild(stars);
- row.appendChild(side);
- return row;
- }
-
- function el(tag, className, text) {
- const node = document.createElement(tag);
- if (className) node.className = className;
- if (text != null) node.textContent = text;
- return node;
- }
-
- function buildCard(p, badge) {
- const url = isGithubUrl(p.url) ? p.url : null;
- const card = el(url ? "a" : "div", "plugin-card");
- card.setAttribute("role", "listitem");
- if (url) {
- card.href = url;
- card.target = "_blank";
- card.rel = "noopener noreferrer";
- }
-
- const head = el("div", "plugin-card-head");
- const lead = el("div", "trend-lead");
- lead.appendChild(avatar(p, 64));
- lead.appendChild(titleOf(p));
- head.appendChild(lead);
- head.appendChild(el("span", "plugin-go", "↗"));
- card.appendChild(head);
- if (badge) card.appendChild(el("div", "plugin-badge", badge));
-
- const desc = el(
- "p",
- "plugin-desc" + (p.description ? "" : " is-empty"),
- p.description || "No description provided.",
- );
- card.appendChild(desc);
-
- const meta = el("div", "plugin-meta-row");
-
- const stars = el("span", "plugin-stat");
- stars.appendChild(el("span", "plugin-star", "★"));
- stars.appendChild(el("span", null, String(p.stars ?? 0)));
- meta.appendChild(stars);
-
- if (p.language) {
- const lang = el("span", "plugin-stat");
- const dot = el("span", "plugin-lang-dot");
- dot.style.background = LANG_COLORS[p.language] || "var(--muted)";
- lang.appendChild(dot);
- lang.appendChild(el("span", null, p.language));
- meta.appendChild(lang);
- }
-
- // Nearly every repository ships exactly one plugin whose name restates the
- // repository name, so only its version earns a place in the meta row.
- const manifests = manifestsOf(p);
- if (manifests.length === 1 && manifests[0].version) {
- meta.appendChild(el("span", "plugin-stat plugin-version", "v" + manifests[0].version));
- }
-
- const updated = timeAgo(p.pushedAt);
- if (updated) meta.appendChild(el("span", "plugin-stat plugin-updated", "updated " + updated));
-
- card.appendChild(meta);
-
- // A monorepo is the case the card title can't answer on its own, so it
- // gets the extra row: how many plugins, and which.
- if (manifests.length > 1) {
- const ships = el("div", "plugin-ships");
- ships.appendChild(el("span", "plugin-ship-count", manifests.length + " plugins"));
- ships.appendChild(
- el("span", "plugin-ship-list", manifests.map(manifestLabel).join(" · ")),
- );
- card.appendChild(ships);
- }
-
- return card;
- }
-
- function manifestsOf(p) {
- return Array.isArray(p.manifests) ? p.manifests : [];
- }
-
- function manifestLabel(m) {
- return m.name || m.id || m.path || "plugin";
- }
-
- function matches(p, q) {
- if (!q) return true;
- const hay = [
- p.fullName,
- p.owner,
- p.name,
- p.description,
- p.language,
- ...(p.topics || []),
- ...manifestsOf(p).flatMap((m) => [m.name, m.id, m.description]),
- ]
- .filter(Boolean)
- .join(" ")
- .toLowerCase();
- return q.split(/\s+/).every((term) => hay.includes(term));
- }
-
- function sortRepos(list, mode) {
- const by = [...list];
- const t = (v) => new Date(v || 0).getTime() || 0;
- if (mode === "recent") by.sort((a, b) => t(b.pushedAt) - t(a.pushedAt));
- // "Newest" means newest to the marketplace, matching the shelf's order;
- // GitHub's createdAt is the fallback for snapshots without firstSeenAt.
- else if (mode === "newest")
- by.sort(
- (a, b) => t(b.firstSeenAt ?? b.createdAt) - t(a.firstSeenAt ?? a.createdAt),
- );
- else if (mode === "name") by.sort((a, b) => (a.fullName || "").localeCompare(b.fullName || ""));
- else if (mode === "trending")
- // Qualified movers first by growth rate, then everything else by raw
- // weekly gain so the list stays fully ordered past the shelf criteria.
- by.sort(
- (a, b) =>
- (trendingScore(b) ?? -1) - (trendingScore(a) ?? -1) ||
- (b.starsDelta7d ?? 0) - (a.starsDelta7d ?? 0) ||
- (b.stars ?? 0) - (a.stars ?? 0),
- );
- else
- by.sort(
- (a, b) => (b.stars ?? 0) - (a.stars ?? 0) || t(b.pushedAt) - t(a.pushedAt),
- );
- return by;
- }
-
- function renderShelves() {
- const trending = repos
- .map((p) => [p, trendingScore(p)])
- .filter(([, score]) => score !== null)
- .sort((a, b) => b[1] - a[1])
- .slice(0, SHELF_SIZE)
- .map(([p]) => p);
- trendGrid.replaceChildren();
- if (trending.length >= SHELF_MIN_CARDS) {
- for (const p of trending) trendGrid.appendChild(buildTrendCard(p));
- }
- trendingShelf.hidden = trending.length < SHELF_MIN_CARDS;
-
- const fresh = repos
- .filter(isNewToHerd)
- .sort((a, b) => new Date(b.firstSeenAt).getTime() - new Date(a.firstSeenAt).getTime())
- .slice(0, SHELF_SIZE);
- const newRows = newShelf.querySelector(".new-rows");
- newRows.replaceChildren();
- for (const p of fresh) newRows.appendChild(buildRow(p, joinedBadge(p)));
- newShelf.hidden = fresh.length < SHELF_MIN_CARDS;
-
- const anyShelf = !trendingShelf.hidden || !newShelf.hidden;
- shelvesWrap.dataset.available = anyShelf ? "1" : "";
- updateShelfVisibility();
- }
-
- function updateShelfVisibility() {
- shelvesWrap.hidden = shelvesWrap.dataset.available !== "1";
- }
-
- function render() {
- const q = searchInput.value.trim().toLowerCase();
- const visible = sortRepos(repos.filter((p) => matches(p, q)), sortSelect.value);
- const shown = visible.slice(0, visibleLimit);
-
- grid.replaceChildren();
- for (const p of shown) grid.appendChild(buildCard(p));
-
- // Grow a page at a time, and name the real remainder on the last step so
- // the button never promises 24 and delivers 5.
- const remaining = visible.length - shown.length;
- moreButton.hidden = remaining === 0;
- if (remaining > 0) {
- moreButton.textContent = "show " + Math.min(PAGE_SIZE, remaining) + " more";
- }
-
- if (visible.length === 0) {
- statusEl.textContent = q
- ? "No plugins match your search."
- : "No plugins are listed yet.";
- statusEl.hidden = false;
- } else {
- statusEl.hidden = true;
- }
- }
-
- function setMeta(data) {
- const parts = [];
- const repoCount = (data && data.repositoryCount) ?? repos.length;
- const total =
- (data && data.pluginCount) ??
- repos.reduce((n, repo) => n + (manifestsOf(repo).length || 1), 0);
- parts.push(total + (total === 1 ? " plugin" : " plugins"));
- parts.push(repoCount + (repoCount === 1 ? " repository" : " repositories"));
- heroCountEl.textContent = total.toLocaleString("en-US");
- heroSummaryEl.textContent =
- (total === 1 ? "plugin" : "plugins") +
- " across " +
- repoCount.toLocaleString("en-US") +
- (repoCount === 1 ? " repository" : " repositories");
- const starsGained = repos.reduce(
- (n, repo) => n + Math.max(repo.starsDelta7d ?? 0, 0),
- 0,
- );
- if (starsGained > 0) parts.push("+" + starsGained.toLocaleString("en-US") + " ★ this week");
- const joined = repos.filter((repo) => {
- const seen = daysSince(repo.firstSeenAt);
- return seen !== null && seen <= 7;
- }).length;
- if (joined > 0) parts.push(joined + " joined this week");
- const ago = timeAgo(data && data.generatedAt);
- if (ago) parts.push("updated " + ago);
- if (usingFallback) parts.push("preview data");
- metaEl.textContent = parts.join(" · ");
- }
-
- function apply(data) {
- repos = Array.isArray(data && data.plugins) ? data.plugins : [];
- setMeta(data);
- renderShelves();
- render();
- }
-
- function showError() {
- repos = [];
- metaEl.textContent = "";
- grid.replaceChildren();
- moreButton.hidden = true;
- statusEl.textContent =
- "The plugin marketplace is warming up. Check back in a few minutes.";
- statusEl.hidden = false;
- }
-
- async function load() {
- // Render the server-seeded data immediately (live in prod and dev; fixture
- // only as a dev offline fallback).
- if (initialData) {
- usingFallback = initialIsFixture;
- apply(initialData);
- }
- // Refresh from the same-origin function in production for the freshest snapshot.
- if (apiUrl) {
- try {
- const res = await fetch(apiUrl, { headers: { accept: "application/json" } });
- if (!res.ok) throw new Error("status " + res.status);
- usingFallback = false;
- apply(await res.json());
- } catch (err) {
- if (!initialData) showError();
- }
- } else if (!initialData) {
- showError();
- }
- }
-
- // A new query or order is a new list, so paging starts over.
- function resetAndRender() {
- visibleLimit = PAGE_SIZE;
- render();
- }
-
- searchInput.addEventListener("input", resetAndRender);
- sortSelect.addEventListener("change", resetAndRender);
- moreButton.addEventListener("click", () => {
- visibleLimit += PAGE_SIZE;
- render();
- });
- for (const button of document.querySelectorAll(".shelf-all")) {
- button.addEventListener("click", () => {
- sortSelect.value = button.dataset.sort;
- resetAndRender();
- grid.scrollIntoView({ behavior: "smooth", block: "start" });
- });
- }
- load();
- </script>
-
- <style is:global>
- .plugins-page {
- padding-bottom: 5rem;
- --plugins-clear-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M1.5 1.5l9 9M10.5 1.5l-9 9' stroke='black' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
- }
-
- /* Reuse .section only for max-width centering, not its 5rem padding + top divider. */
- .plugins-page .section {
- padding-block: 0;
- border-top: none;
- }
-
- /* Everything below the hero sits inside the same horizontal gutter the
- hero uses, so text never touches the page's column lines. Selectors
- outrank site.css's `body.site .plugins-page .section` padding reset. */
- .plugins-page #plugins-shelves,
- body.site .plugins-page .section.plugins-results,
- body.site .plugins-page .section.plugins-publish {
- padding-inline: var(--gut);
- }
-
- .plugins-page .plugins-hero {
- padding-top: 3rem;
- }
-
- .plugins-hero h2 {
- margin: 0;
- color: var(--ink);
- font-family: var(--mono);
- font-weight: 400;
- letter-spacing: -0.04em;
- line-height: 1.05;
- font-size: clamp(2rem, 4vw, 3rem);
- }
-
- .plugins-lede {
- max-width: 640px;
- margin: 1.1rem 0 0;
- color: var(--ink-soft);
- font-size: clamp(1rem, 1.6vw, 1.15rem);
- line-height: 1.6;
- }
-
- .plugins-lede code,
- .plugins-trust code,
- .plugins-publish-card code {
- font-family: var(--mono);
- font-size: 0.85em;
- background: var(--bg-elevated);
- border: 1px solid var(--line);
- border-radius: var(--radius-sm);
- padding: 0.1em 0.35em;
- white-space: nowrap;
- }
-
- .plugins-trust {
- max-width: 640px;
- margin: 1.1rem 0 0;
- color: var(--muted);
- font-size: 0.85rem;
- line-height: 1.55;
- }
-
- .plugins-trust .status-dot {
- display: inline-block;
- margin-right: 0.4rem;
- vertical-align: middle;
- }
-
- .plugins-trust a {
- color: var(--accent);
- text-decoration: underline;
- text-underline-offset: 2px;
- }
-
- /* Controls */
- .plugins-controls {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 0.75rem;
- margin-top: 1.5rem;
- }
-
- .plugins-search-wrap {
- position: relative;
- flex: 1 1 18rem;
- display: flex;
- align-items: center;
- }
-
- .plugins-search-icon {
- position: absolute;
- left: 0.7rem;
- color: var(--muted-2);
- font-family: var(--mono);
- font-size: 0.9rem;
- pointer-events: none;
- }
-
- .plugins-search {
- width: 100%;
- padding: 0.6rem 0.8rem 0.6rem 1.7rem;
- background: var(--bg-elevated);
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- color: var(--ink);
- font-family: var(--mono);
- font-size: 0.85rem;
- }
-
- .plugins-search:focus {
- outline: none;
- border-color: var(--accent);
- }
-
- /* Chromium paints the native clear button in the OS accent colour, which
- belongs to no ground the site defines. Redraw it from our own tokens. */
- .plugins-search::-webkit-search-cancel-button {
- -webkit-appearance: none;
- appearance: none;
- width: 0.7rem;
- height: 0.7rem;
- cursor: pointer;
- background: var(--muted-2);
- -webkit-mask: var(--plugins-clear-icon) center / contain no-repeat;
- mask: var(--plugins-clear-icon) center / contain no-repeat;
- }
-
- .plugins-search::-webkit-search-cancel-button:hover {
- background: var(--ink);
- }
-
- .plugins-sort-wrap {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- }
-
- .plugins-sort-label {
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.78rem;
- text-transform: lowercase;
- letter-spacing: 0.06em;
- }
-
- .plugins-sort {
- padding: 0.55rem 0.7rem;
- background: var(--bg-elevated);
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- color: var(--ink);
- font-family: var(--mono);
- font-size: 0.82rem;
- cursor: pointer;
- }
-
- .plugins-sort:focus {
- outline: none;
- border-color: var(--accent);
- }
-
- .plugins-meta {
- margin: 1rem 0 0;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.78rem;
- letter-spacing: 0.04em;
- }
-
- /* Shelves */
- #plugins-shelves {
- margin-top: 3.5rem;
- }
-
- body.site .plugins-page .section.plugins-shelf {
- margin-top: 4.5rem;
- }
-
- body.site .plugins-page #plugins-shelves > .section.plugins-shelf:first-child {
- margin-top: 0;
- }
-
- .shelf-head {
- display: flex;
- align-items: flex-end;
- justify-content: space-between;
- gap: 1rem;
- margin-bottom: 1.25rem;
- }
-
- /* Outranks style.css's `.section h2` mono heading rule. */
- body.site .plugins-page h2.shelf-title {
- margin: 0;
- color: var(--ink);
- font-family: var(--disp);
- font-weight: 800;
- font-size: 21px;
- letter-spacing: -0.03em;
- line-height: 1.2;
- }
-
- .shelf-sub {
- margin: 0.35rem 0 0;
- color: var(--muted);
- font-size: 0.82rem;
- }
-
- .shelf-all {
- flex: 0 0 auto;
- padding: 0;
- background: none;
- border: none;
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.82rem;
- cursor: pointer;
- text-decoration: underline;
- text-underline-offset: 3px;
- }
-
- .shelf-all:hover {
- color: var(--ink);
- }
-
- .plugin-badge {
- align-self: flex-start;
- padding: 0.15rem 0.5rem;
- background: color-mix(in srgb, var(--accent) 10%, transparent);
- border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
- border-radius: var(--radius-sm);
- color: var(--accent);
- font-family: var(--mono);
- font-size: 0.74rem;
- letter-spacing: 0.02em;
- white-space: nowrap;
- }
-
- .plugin-avatar {
- width: 1.5rem;
- height: 1.5rem;
- flex: 0 0 auto;
- border-radius: var(--radius-sm);
- background: var(--bg);
- border: 1px solid var(--line);
- }
-
- .trend-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.85rem;
- }
-
- .plugin-trend-card {
- min-height: 0;
- gap: 0.65rem;
- padding: 1.1rem 1.2rem;
- }
-
- .trend-lead {
- display: flex;
- align-items: center;
- gap: 0.6rem;
- min-width: 0;
- }
-
- .new-rows {
- display: flex;
- flex-direction: column;
- }
-
- .plugin-row {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 0.65rem 0.5rem;
- border-top: 1px solid var(--line);
- border-radius: var(--radius-sm);
- transition: background 0.12s ease;
- min-width: 0;
- }
-
- .plugin-row:last-child {
- border-bottom: 1px solid var(--line);
- }
-
- a.plugin-row:hover {
- background: var(--bg-elevated);
- }
-
- .plugin-row-body {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- min-width: 0;
- }
-
- .plugin-row-body .plugin-title {
- font-size: 0.85rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .plugin-row-desc {
- color: var(--muted);
- font-size: 0.78rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .plugin-row-desc.is-empty {
- color: var(--muted-2);
- font-style: italic;
- }
-
- .plugin-row-side {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- margin-left: auto;
- flex: 0 0 auto;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.75rem;
- }
-
- .plugin-row-note {
- color: var(--accent);
- white-space: nowrap;
- }
-
- .plugins-browse-head {
- margin-bottom: 1rem;
- padding-top: 2.25rem;
- border-top: 1px solid var(--line);
- }
-
- .plugins-browse-head[hidden] {
- display: none;
- }
-
- @media (max-width: 56rem) {
- .trend-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
- }
-
- @media (max-width: 38rem) {
- .trend-grid {
- grid-template-columns: minmax(0, 1fr);
- }
- }
-
- /* Grid */
- body.site .plugins-page .section.plugins-results {
- margin-top: 4.5rem;
- }
-
- .plugins-results .plugins-grid {
- margin-top: 1.5rem;
- }
-
- .plugins-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
- gap: 0.85rem;
- }
-
- .plugin-card {
- display: flex;
- flex-direction: column;
- gap: 0.7rem;
- padding: 1.25rem;
- background: var(--bg-elevated);
- border: 1px solid var(--line);
- border-radius: var(--radius-md);
- transition: border-color 0.12s ease, transform 0.12s ease;
- min-height: 8.5rem;
- }
-
- a.plugin-card:hover {
- border-color: var(--accent);
- transform: translateY(-2px);
- }
-
- .plugin-card-head {
- display: flex;
- align-items: flex-start;
- justify-content: space-between;
- gap: 0.5rem;
- }
-
- .plugin-title {
- font-family: var(--mono);
- font-size: 0.95rem;
- line-height: 1.3;
- word-break: break-word;
- }
-
- .plugin-owner {
- color: var(--muted);
- }
-
- .plugin-name {
- color: var(--ink);
- font-weight: 600;
- }
-
- .plugin-go {
- color: var(--muted-2);
- font-family: var(--mono);
- flex: 0 0 auto;
- transition: color 0.12s ease;
- }
-
- a.plugin-card:hover .plugin-go {
- color: var(--accent);
- }
-
- .plugin-desc {
- margin: 0;
- color: var(--ink-soft);
- font-size: 0.88rem;
- line-height: 1.5;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- overflow: hidden;
- }
-
- .plugin-desc.is-empty {
- color: var(--muted-2);
- font-style: italic;
- }
-
- .plugin-meta-row {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 0.9rem;
- margin-top: auto;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.78rem;
- }
-
- .plugin-stat {
- display: inline-flex;
- align-items: center;
- gap: 0.35rem;
- }
-
- .plugin-star {
- color: var(--yellow, #d4a72c);
- }
-
- .plugin-lang-dot {
- width: 0.6rem;
- height: 0.6rem;
- border-radius: 50%;
- flex: 0 0 auto;
- }
-
- .plugin-updated {
- margin-left: auto;
- color: var(--muted-2);
- }
-
- /* What the repository ships. Sits below the repo stats, separated by a rule,
- so the repository stays the primary identity of the card. */
- .plugin-ships {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- gap: 0.45rem;
- padding-top: 0.7rem;
- border-top: 1px solid var(--line);
- font-family: var(--mono);
- font-size: 0.78rem;
- line-height: 1.5;
- min-width: 0;
- }
-
- .plugin-version {
- color: var(--muted-2);
- }
-
- .plugin-ship-count {
- flex: 0 0 auto;
- padding: 0.05rem 0.4rem;
- border: 1px solid var(--line);
- border-radius: var(--radius-sm);
- color: var(--muted-2);
- }
-
- .plugin-ship-list {
- align-self: stretch;
- min-width: 0;
- color: var(--muted);
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- overflow: hidden;
- }
-
- .plugins-status {
- padding: 3rem 1rem;
- text-align: center;
- color: var(--muted);
- font-family: var(--mono);
- font-size: 0.85rem;
- }
-
- .plugins-more {
- display: flex;
- margin: 2rem auto 0;
- cursor: pointer;
- }
-
- .plugins-more[hidden] {
- display: none;
- }
-
- /* Publish */
- .plugins-publish {
- margin-top: 3.5rem;
- }
-
- .plugins-publish-card {
- padding: 2rem;
- background: var(--bg-elevated);
- border: 1px solid var(--line);
- border-radius: var(--radius-lg);
- }
-
- .plugins-publish-card h3 {
- margin: 0.25rem 0 0;
- color: var(--ink);
- font-family: var(--mono);
- font-weight: 400;
- font-size: 1.4rem;
- letter-spacing: -0.02em;
- }
-
- .plugins-publish-card p {
- max-width: 620px;
- margin: 0.8rem 0 0;
- color: var(--ink-soft);
- line-height: 1.6;
- }
-
- .plugins-publish-actions {
- display: flex;
- flex-wrap: wrap;
- gap: 0.6rem;
- margin-top: 1.5rem;
- }
-
- @media (max-width: 38rem) {
- .plugins-meta {
- margin-left: 0;
- width: 100%;
- }
- }
- </style>
-</SiteLayout>
diff --git a/website/src/site-data.ts b/website/src/site-data.ts
deleted file mode 100644
index 94836fe7..00000000
--- a/website/src/site-data.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-import { readdir, readFile } from 'node:fs/promises';
-import { resolve } from 'node:path';
-
-/* The numbers the site's chrome shows, resolved once per build.
- Stars, installs and plugin counts come from the same R2 snapshots /stats/
- and /plugins/ read; the version comes from latest.json, which release CI
- owns. Nothing here is hand-maintained, so no figure on the site can go
- stale independently of a deploy.
-
- Memoised because SiteLayout renders on every blog post, and a build that
- renders many pages should still fetch once. */
-
-export type SiteStats = {
- starCount?: number;
- installCount?: number;
- pluginCount?: number;
-};
-
-async function snapshot(url: string): Promise<any | null> {
- try {
- const res = await fetch(url);
- return res.ok ? await res.json() : null;
- } catch {
- return null;
- }
-}
-
-async function load(): Promise<SiteStats> {
- const [stats, plugins] = await Promise.all([
- snapshot('https://assets.herdr.dev/stats/stats.json'),
- snapshot('https://assets.herdr.dev/plugins/index.json'),
- ]);
-
- return {
- starCount: stats?.stars?.total,
- installCount: stats?.downloads
- ? (stats.downloads.github || 0) + (stats.downloads.brew || 0)
- : undefined,
- /* `pluginCount` counts validated manifests, which is what the marketplace
- lists. `source.totalCount` is the raw GitHub topic search and still
- includes blacklisted repositories and ones with no manifest. */
- pluginCount: plugins?.pluginCount ?? plugins?.plugins?.length,
- };
-}
-
-let statsPromise: Promise<SiteStats> | null = null;
-
-export function siteStats(): Promise<SiteStats> {
- statsPromise ??= load();
- return statsPromise;
-}
-
-/* latest.json carries the full release notes, so read and pick rather than
- importing it and bundling all of that into the page. */
-async function readVersion(): Promise<string | null> {
- try {
- const raw = await readFile(new URL('../latest.json', import.meta.url), 'utf8');
- return JSON.parse(raw).version ?? null;
- } catch {
- return null;
- }
-}
-
-let versionPromise: Promise<string | null> | null = null;
-
-export function releaseVersion(): Promise<string | null> {
- versionPromise ??= readVersion();
- return versionPromise;
-}
-
-/* How many agents Herdr detects out of the box, counted from the bundled
- manifests. The site is built from the same repo as the binary, so the number
- tracks the code and cannot drift the way a written-down one would — add a
- manifest and the homepage says so on the next deploy. */
-async function countAgentManifests(): Promise<number | null> {
- /* Resolved from cwd, not import.meta.url: once Vite bundles this module for
- the build the module URL no longer points at the source file, so a
- relative URL silently found nothing and the line vanished from dist while
- still rendering in dev. Both candidates cover running the build from
- website/ or from the repo root. */
- for (const rel of ['../src/detect/manifests', 'src/detect/manifests']) {
- try {
- const files = await readdir(resolve(process.cwd(), rel));
- const count = files.filter((f) => f.endsWith('.toml')).length;
- if (count > 0) return count;
- } catch {
- /* try the next candidate */
- }
- }
- return null;
-}
-
-let agentCountPromise: Promise<number | null> | null = null;
-
-export function agentCount(): Promise<number | null> {
- agentCountPromise ??= countAgentManifests();
- return agentCountPromise;
-}
-
-/* A fetch that failed at build shows an em dash. A stale hardcoded number
- would look authoritative and be wrong, which is worse. */
-export const fmt = (n: unknown): string =>
- typeof n === 'number' ? n.toLocaleString('en-US') : '—';
diff --git a/website/src/styles/starlight.css b/website/src/styles/starlight.css
deleted file mode 100644
index 39eef15f..00000000
--- a/website/src/styles/starlight.css
+++ /dev/null
@@ -1,273 +0,0 @@
-@font-face {
- font-family: "JetBrains Mono";
- font-style: normal;
- font-weight: 400 700;
- font-display: swap;
- src: url("/assets/jbm.woff2") format("woff2");
- unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC,
- U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
- U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
-
-:root {
- --sl-font: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
- --sl-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
- --sl-content-width: 54rem;
- --sl-sidebar-width: 18.5rem;
-}
-
-/* Docs share the site's ground and mauve. Prose stays in a reading sans
- rather than the marketing mono — docs is a tool, not a statement.
-
- The ramp is the marketing scale, not a separate one: the same near-neutral
- ground and the same text triad, so the two surfaces cannot drift apart on
- the next palette change. Chroma is drained for the reason it was drained
- there — saturated blue at low luminance softens the edges of light text,
- and a side-by-side read easier without it. Surfaces are luminance-matched
- to what they replace; text is taken straight from the marketing scale,
- which lands every step at or above its old contrast except gray-3, and
- that one stays clear of AA. Contrast on the ground: white 14.7, gray-1
- 11.9, gray-2 9.3, gray-3 5.3, gray-4 4.2, accent 8.8. */
-:root,
-:root[data-theme="dark"] {
- --sl-color-accent-low: #3f364b;
- --sl-color-accent: #cba6f7;
- --sl-color-accent-high: #ddc4fb;
- --sl-color-white: #eae8ee;
- --sl-color-gray-1: #d5d1dd;
- --sl-color-gray-2: #bdb9c9;
- --sl-color-gray-3: #8e8a98;
- --sl-color-gray-4: #7c7887;
- --sl-color-gray-5: #4a4851;
- --sl-color-gray-6: #35353d;
- --sl-color-gray-7: #26262b;
- --sl-color-black: #17171a;
- --sl-color-bg: #17171a;
- --sl-color-bg-nav: #1e1e22;
- --sl-color-bg-sidebar: #1e1e22;
- --sl-color-bg-inline-code: #26262b;
- --sl-color-hairline: #26262b;
- --sl-color-hairline-light: #35353d;
-}
-
-/* the brand display face, same pairing as the marketing pages:
- Archivo for the branded headings, mono for everything code-adjacent */
-:root { --sl-font-display: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif; }
-
-/* paper — the same ground the marketing pages use, with the mauve dropped to
- a value that holds on a light background */
-:root[data-theme="light"] {
- --sl-color-accent-low: #ded3f2;
- --sl-color-accent: #8839ef;
- --sl-color-accent-high: #5b2ba3;
- --sl-color-white: #15140f;
- --sl-color-gray-1: #26241d;
- --sl-color-gray-2: #55534a;
- --sl-color-gray-3: #6f6c60;
- --sl-color-gray-4: #86826f;
- --sl-color-gray-5: #a8a493;
- --sl-color-gray-6: #cbc5b6;
- --sl-color-gray-7: #e2ded4;
- --sl-color-black: #efece5;
- --sl-color-bg: #efece5;
- --sl-color-bg-nav: #e7e3da;
- --sl-color-bg-sidebar: #e7e3da;
- --sl-color-bg-inline-code: #ddd8cc;
- --sl-color-hairline: #e2ded4;
- --sl-color-hairline-light: #cbc5b6;
-}
-
-.site-title {
- font-family: var(--sl-font-mono);
- font-weight: 700;
- letter-spacing: -0.04em;
-}
-
-.docs-brand-logo {
- position: relative;
- display: inline-block;
- width: 32px;
- height: 32px;
- flex: 0 0 auto;
- border: 1px solid var(--sl-color-hairline);
- border-radius: 4px;
- background: var(--sl-color-bg-nav);
-}
-
-.docs-brand-logo::before {
- content: "";
- position: absolute;
- inset: 2px;
- background: var(--sl-color-white);
- -webkit-mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
- mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
-}
-
-.docs-hero-logo {
- display: block;
- width: min(20rem, 62vw);
- aspect-ratio: 1;
- background: var(--sl-color-white);
- -webkit-mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
- mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
-}
-
-.sl-markdown-content {
- font-size: 1rem;
- line-height: 1.65;
-}
-
-.sl-markdown-content h1,
-.hero h1 {
- letter-spacing: -0.03em;
- line-height: 1.1;
- font-weight: 900;
- font-size: clamp(2rem, 5vw, 3.2rem);
- font-family: var(--sl-font-display);
- letter-spacing: -0.045em;
-}
-
-.sl-markdown-content h2 {
- margin-top: 2.4rem;
- letter-spacing: -0.03em;
- font-family: var(--sl-font-display);
- font-weight: 800;
-}
-
-.sl-markdown-content h3 {
- letter-spacing: -0.01em;
- font-family: var(--sl-font-mono);
- font-weight: 400;
-}
-
-.sl-markdown-content > p:first-child {
- font-size: 1.05rem;
- color: var(--sl-color-gray-1);
-}
-
-#starlight__sidebar a[aria-current="page"] {
- background: color-mix(in srgb, var(--sl-color-accent) 8%, transparent);
- color: var(--sl-color-accent-high);
- box-shadow: inset 2px 0 0 var(--sl-color-accent);
-}
-
-.mobile-doc-shots {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
- gap: 1rem;
- margin: 1.25rem 0;
-}
-
-.mobile-doc-shots figure {
- margin: 0;
-}
-
-.mobile-doc-shots img {
- display: block;
- width: 100%;
- border: 1px solid var(--sl-color-hairline);
- border-radius: 4px;
-}
-
-.mobile-doc-shots figcaption {
- margin-top: 0.45rem;
- color: var(--sl-color-gray-3);
- font-size: var(--sl-text-sm);
- text-align: center;
-}
-
-.sl-markdown-content a:not(:where(.not-content *)) {
- text-decoration-thickness: 1px;
- text-underline-offset: 0.18em;
- color: var(--sl-color-accent);
-}
-
-.sl-markdown-content .heading-link-copy-feedback {
- position: absolute;
- z-index: 10;
- bottom: calc(100% + 0.4rem);
- inset-inline-start: 50%;
- padding: 0.25rem 0.45rem;
- border: 1px solid var(--sl-color-hairline-light);
- border-radius: 3px;
- background: var(--sl-color-bg-nav);
- color: var(--sl-color-white);
- font-family: var(--sl-font);
- font-size: var(--sl-text-xs);
- font-weight: 500;
- line-height: 1.2;
- white-space: nowrap;
- pointer-events: none;
- transform: translateX(-50%);
- animation: heading-link-copied 1.4s ease both;
-}
-
-@keyframes heading-link-copied {
- 0% { opacity: 0; transform: translate(-50%, 0.25rem); }
- 15%, 75% { opacity: 1; transform: translate(-50%, 0); }
- 100% { opacity: 0; transform: translate(-50%, -0.15rem); }
-}
-
-@media (prefers-reduced-motion: reduce) {
- .sl-markdown-content .heading-link-copy-feedback {
- animation: none;
- }
-}
-
-.sl-markdown-content code:not(:where(.not-content *)) {
- border: 1px solid var(--sl-color-hairline);
- border-radius: 2px;
- font-size: 0.88em;
- background: var(--sl-color-bg-inline-code);
-}
-
-.sl-markdown-content pre {
- border: 1px solid var(--sl-color-hairline);
- border-radius: 4px;
-}
-
-.expressive-code {
- margin: 1rem 0 1.35rem;
-}
-
-.expressive-code .frame {
- border: 1px solid var(--sl-color-hairline) !important;
- border-radius: 4px !important;
- box-shadow: none !important;
- overflow: hidden;
-}
-
-.expressive-code .frame.is-terminal {
- --button-spacing: 0.4rem;
-}
-
-.expressive-code .frame.is-terminal .header {
- display: none;
-}
-
-.expressive-code .frame pre {
- border: 0 !important;
- border-radius: 0 !important;
-}
-
-.expressive-code .frame.has-title:not(.is-terminal) .header {
- background: var(--sl-color-bg-nav) !important;
- border-color: var(--sl-color-hairline) !important;
-}
-
-.sl-markdown-content .card {
- border-color: var(--sl-color-hairline);
- background:
- linear-gradient(180deg, color-mix(in srgb, var(--sl-color-accent) 4%, transparent), transparent 58%),
- var(--sl-color-black);
- border-radius: 4px;
-}
-
-.sl-markdown-content .card .title {
- color: var(--sl-color-white);
-}
-
-.hero img {
- image-rendering: auto;
- border-radius: 4px;
-}