diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-09-01 14:48:45 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-09-01 14:48:45 +0300 |
| commit | 8a6d697308162874a236c84aac0b0f8c7ac01f83 (patch) | |
| tree | ed7dc7e8c6f50d66bde721fae78576aede929f66 /website | |
| parent | b54a78aa510b87d1e3b56c619b72eaeb59e4a2a1 (diff) | |
refactor: separate website presentation from runtime
Diffstat (limited to 'website')
116 files changed, 0 insertions, 16794 deletions
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/agent-detection/amp.toml b/website/agent-detection/amp.toml deleted file mode 100644 index 1fc5dfa6..00000000 --- a/website/agent-detection/amp.toml +++ /dev/null @@ -1,65 +0,0 @@ -id = "amp" -version = "2026.07.09.1" -min_engine_version = 2 -updated_at = "2026-07-09T00:00:00Z" -aliases = ["amp-local"] - -[[rules]] -id = "osc_title_plugin_confirmation_blocked" -state = "blocked" -priority = 1100 -region = "osc_title" -visible_blocker = true -contains = ["Plugin confirmation needed"] - -[[rules]] -id = "osc_title_working" -state = "working" -priority = 1050 -region = "osc_title" -visible_working = true -regex = ['^[\x{2800}-\x{28FF}] '] - -[[rules]] -id = "approval_footer" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -any = [ - { contains = ["waiting for approval"] }, - { contains = ["invoke tool"] }, - { contains = ["run this command?"] }, - { contains = ["allow editing file:"] }, - { contains = ["allow creating file:"] }, - { contains = ["confirm tool call"] }, - { contains = ["approve"], any = [{ contains = ["allow all for this session"] }, { contains = ["allow all for every session"] }, { contains = ["allow file for every session"] }, { contains = ["deny with feedback"] }] }, -] - -[[rules]] -id = "status_footer_working" -state = "working" -priority = 200 -region = "bottom_non_empty_lines(5)" -visible_working = true -line_regex = ['(?i)^\s*╰\s+\S+\s+(thinking|streaming|running tools|waiting)\s+─'] - -[[rules]] -id = "esc_cancel_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -contains = ["esc to cancel"] - -[[rules]] -id = "osc_title_idle" -state = "idle" -priority = 50 -region = "osc_title" -visible_idle = true -contains = [" - amp - "] -not = [ - { regex = ['^[\x{2800}-\x{28FF}] '] }, - { contains = ["Plugin confirmation needed"] }, -] diff --git a/website/agent-detection/antigravity.toml b/website/agent-detection/antigravity.toml deleted file mode 100644 index 8b9bcfcf..00000000 --- a/website/agent-detection/antigravity.toml +++ /dev/null @@ -1,33 +0,0 @@ -id = "agy" -version = "2026.06.24.1" -min_engine_version = 1 -updated_at = "2026-06-24T00:00:00Z" -aliases = ["antigravity", "antigravity-cli"] - -[[rules]] -id = "permission_prompt" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -contains = ["requesting permission for:"] -any = [ - { contains = ["do you want to proceed?"] }, - { contains = ["tab amend", "edit command"] }, -] - -[[rules]] -id = "spinner_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -line_regex = ['^\s*[\u2800-\u28FF]+\s+\p{Alphabetic}+\w*ing\b'] - -[[rules]] -id = "background_tasks_working" -state = "working" -priority = 90 -region = "bottom_non_empty_lines(5)" -visible_working = true -line_regex = ['(?i)·\s*[1-9][0-9]*\s+task'] diff --git a/website/agent-detection/claude.toml b/website/agent-detection/claude.toml deleted file mode 100644 index 55adacd6..00000000 --- a/website/agent-detection/claude.toml +++ /dev/null @@ -1,226 +0,0 @@ -id = "claude" -version = "2026.08.29.1" -min_engine_version = 2 -updated_at = "2026-08-29T00:00:00Z" -aliases = ["claude-code"] - -[[rules]] -id = "osc_title_working" -state = "working" -priority = 1100 -region = "osc_title" -visible_working = true -# Braille covers <= 2.1.227; half-circles are the 2.1.228 busy spinner. -regex = ['^[\x{2800}-\x{28FF}\x{25D0}-\x{25D3}] '] - -[[rules]] -id = "live_turn_working" -state = "working" -priority = 970 -region = "bottom_non_empty_lines(12)" -visible_working = true -any = [ - { line_regex = ['^\s*[⏸⏵].*esc to interrupt(?:\s|·|$)'] }, - { line_regex = ['^\s*[\x{002A}\x{00B7}\x{2722}\x{2736}\x{273B}\x{273D}]\s+\S.*…(?:\s+\(\d+[smh](?:\s|·)|\s*$)'] }, -] - -[[rules]] -id = "background_shell_working" -state = "working" -priority = 965 -region = "bottom_non_empty_lines(5)" -visible_working = true -line_regex = ['^\s*[⏸⏵].*·\s+[1-9]\d*\s+shells?\s+(?:·|$)'] - -[[rules]] -id = "background_agents_working" -state = "working" -priority = 965 -region = "last_non_empty_above_prompt_box" -visible_working = true -line_regex = ['^\s*[\x{002A}\x{00B7}\x{2722}\x{2736}\x{273B}\x{273D}]\s+Waiting for [1-9]\d* background agents? to finish\s*$'] - -[[rules]] -id = "background_mcp_task_working" -state = "working" -priority = 965 -region = "bottom_non_empty_lines(12)" -visible_working = true -# Claude renders activity summaries at column zero; wrapped continuations are indented. -# Keeping that shape prevents user prompt text from impersonating this signal. -regex = ['(?m)^[\x{002A}\x{00B7}\x{2722}\x{2736}\x{273B}\x{273D}][ \t]+\S[^\n]*?(?:\n[ \t]+[^\n]*?){0,3}·(?:[ \t]+|\n[ \t]*)[1-9]\d*(?:[ \t]+|\n[ \t]*)MCP(?:[ \t]+|\n[ \t]*)tasks?(?:[ \t]+|\n[ \t]*)still(?:[ \t]+|\n[ \t]*)running[ \t]*$'] -not = [ - { contains = ["do you want to proceed?"] }, - { contains = ["esc to cancel"] }, - { contains = ["waiting for permission"] }, - { contains = ["do you want to allow this connection?"] }, - { contains = ["tab to amend"] }, - { contains = ["ctrl+e to explain"] }, -] - -[[rules]] -id = "btw_overlay_working" -state = "working" -priority = 975 -region = "bottom_non_empty_lines(5)" -visible_working = true -line_regex = [ - '^\s*/btw(?:\s|$)', - '(?i)esc to close\s*$', -] - -[[rules]] -id = "transcript_viewer" -state = "unknown" -priority = 1000 -region = "bottom_non_empty_lines(3)" -skip_state_update = true -contains = ["showing detailed transcript"] -any = [ - { contains = ["ctrl+o", "to toggle"] }, - { contains = ["ctrl+e", "show all"] }, - { contains = ["ctrl+e", "collapse"] }, - { contains = ["↑↓ scroll"] }, - { contains = ["? for shortcuts"] }, -] - -[[rules]] -id = "live_blocked_form" -state = "blocked" -priority = 980 -region = "after_last_horizontal_rule" -visible_blocker = true -contains = ["esc to cancel"] -any = [ - { contains = ["enter to confirm"] }, - { contains = ["enter to select"], any = [ - { contains = ["tab/arrow keys to navigate"] }, - { contains = ["arrow keys to navigate"] }, - { contains = ["arrows to navigate"] }, - { contains = ["↑/↓ to navigate"] }, - { contains = ["↑↓ to navigate"] }, - ] }, -] - -[[rules]] -id = "dynamic_workflow_prompt" -state = "blocked" -priority = 980 -region = "whole_recent" -visible_blocker = true -contains = ["run a dynamic workflow?", "esc to cancel"] - -[[rules]] -id = "mcp_elicitation_prompt" -state = "blocked" -priority = 980 -region = "whole_recent" -visible_blocker = true -# MCP elicitation dialogs (elicitation/create) show Accept/Decline controls -# with an "Esc to cancel" footer but no Enter hint, so live_blocked_form -# cannot see them (issue #3283). Gate on the invariant header line, the -# Accept/Decline control line, and the cancel footer. -contains = ["esc to cancel"] -line_regex = ['(?i)^\s*MCP server ["\x{201C}].+["\x{201D}] requests your input\s*$'] -all = [ - { any = [ - { line_regex = ['^\s*\x{276F}?\s*Accept\b'] }, - { line_regex = ['^\s*\x{276F}?\s*Decline\b'] }, - ] }, -] - -[[rules]] -id = "live_prompt_box" -state = "idle" -priority = 950 -region = "prompt_box_body" -visible_idle = true -line_regex = ['^\s*❯'] -not = [ - { contains = ["enter to select"] }, - { contains = ["esc to cancel"] }, - { contains = ["tab/arrow keys"] }, - { contains = ["arrow keys to navigate"] }, - { contains = ["↑/↓ to navigate"] }, -] - -[[rules]] -id = "model_picker_menu" -state = "unknown" -priority = 900 -region = "whole_recent" -skip_state_update = true -contains = ["select model", "enter to set as default", "esc to cancel"] -not = [ - { contains = ["do you want to proceed?"] }, - { contains = ["enter to select"] }, -] - -[[rules]] -id = "bash_permission_prompt" -state = "blocked" -priority = 850 -region = "whole_recent" -visible_blocker = true -contains = ["do you want to proceed?"] -any = [ - { contains = ["bash command"] }, - { contains = ["bash("] }, - { contains = ["contains expansion"] }, - { contains = ["tab to amend"] }, - { contains = ["ctrl+e to explain"] }, -] -all = [ - { any = [{ line_regex = ['(?i)^\s*❯?\s*yes\b'] }, { line_regex = ['(?i)^\s*1\.\s*yes\b'] }, { line_regex = ['(?i)^\s*2\.\s*no\b'] }] }, -] - -[[rules]] -id = "generic_permission_prompt" -state = "blocked" -priority = 840 -region = "after_last_horizontal_rule" -visible_blocker = true -contains = ["do you want to proceed?", "esc to cancel"] -all = [ - { any = [ - { line_regex = ['(?i)^\s*❯?\s*1\.\s*yes\b'] }, - { line_regex = ['(?i)^\s*2\.\s*yes\b'] }, - { line_regex = ['(?i)^\s*2\.\s*no\b'] }, - { line_regex = ['(?i)^\s*3\.\s*no\b'] }, - ] }, -] - -[[rules]] -id = "legacy_no_prompt_blocker" -state = "blocked" -priority = 300 -region = "whole_recent" -any = [ - { contains = ["do you want to"], any = [{ contains = ["yes"] }, { contains = ["❯"] }] }, - { contains = ["would you like to"], any = [{ contains = ["yes"] }, { contains = ["❯"] }] }, - { contains = ["waiting for permission"] }, - { contains = ["do you want to allow this connection?"] }, - { contains = ["tab to amend"] }, - { contains = ["ctrl+e to explain"] }, - { contains = ["do you want to proceed?", "esc to cancel"] }, - { contains = ["review your answers"] }, - { contains = ["skip interview and plan immediately"] }, -] -not = [ - { regex = ['(?m)^\s*❯\s*$'] }, -] - -[[rules]] -id = "osc_title_idle" -state = "idle" -priority = 250 -region = "osc_title" -visible_idle = true -regex = ['^\x{2733} '] - -[[rules]] -id = "osc_progress_idle" -state = "idle" -priority = 250 -region = "osc_progress" -regex = ['^4;0'] diff --git a/website/agent-detection/cline.toml b/website/agent-detection/cline.toml deleted file mode 100644 index b30f4417..00000000 --- a/website/agent-detection/cline.toml +++ /dev/null @@ -1,26 +0,0 @@ -id = "cline" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" - -[[rules]] -id = "tool_permission" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -any = [ - { contains = ["let cline use this tool"] }, - { contains = ["[act mode]", "execute command?", "yes"] }, - { contains = ["[act mode]", "use this tool?", "yes"] }, - { contains = ["[plan mode]", "execute command?", "yes"] }, - { contains = ["[plan mode]", "use this tool?", "yes"] }, -] - -[[rules]] -id = "default_cline_working" -state = "working" -priority = -10 -region = "whole_recent" -visible_working = true -regex = ['(?s).+'] diff --git a/website/agent-detection/codex.toml b/website/agent-detection/codex.toml deleted file mode 100644 index 6833f390..00000000 --- a/website/agent-detection/codex.toml +++ /dev/null @@ -1,89 +0,0 @@ -id = "codex" -version = "2026.08.28.1" -min_engine_version = 3 -updated_at = "2026-08-28T00:00:00Z" - -[[rules]] -id = "osc_title_blocked" -state = "blocked" -priority = 1100 -region = "osc_title" -visible_blocker = true -contains = ["Action Required"] - -[[rules]] -id = "osc_title_working" -state = "working" -priority = 1050 -region = "osc_title" -visible_working = true -regex = ['(?:^| )[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏](?: |$)'] - -[[rules]] -id = "transcript_viewer" -state = "unknown" -priority = 1000 -region = "after_last_prompt_marker" -skip_state_update = true -contains = ["↑/↓ to scroll", "pgup/pgdn to", "home/end to jump", "q to quit"] -any = [ - { contains = ["esc to edit prev"] }, - { contains = ["esc/← to edit prev"] }, -] - -[[rules]] -id = "trust_directory" -state = "blocked" -priority = 950 -region = "top_non_empty_lines(20)" -visible_blocker = true -all = [ - { regex = ['\A> You are in [^\r\n]+(?:\r?\n|$)'] }, - { regex = ['(?s)Do\s+you\s+trust\s+the\s+contents\s+of\s+this\s+directory\?'] }, -] - -[[rules]] -id = "live_strong_blocker" -state = "blocked" -priority = 900 -region = "after_last_prompt_marker" -visible_blocker = true -any = [ - { contains = ["press enter to confirm or esc to cancel"] }, - { contains = ["enter to submit answer"] }, - { contains = ["enter to submit all"] }, - { contains = ["allow command?"] }, -] - -[[rules]] -id = "weak_blocker" -state = "blocked" -priority = 600 -region = "whole_recent_without_current_prompt_marker" -any = [ - { contains = ["[y/n]"] }, - { contains = ["yes (y)"] }, - { contains = ["do you want to"], any = [{ contains = ["yes"] }, { contains = ["❯"] }] }, - { contains = ["would you like to"], any = [{ contains = ["yes"] }, { contains = ["❯"] }] }, -] - -[[rules]] -id = "screen_working_fallback" -state = "working" -priority = 500 -region = "bottom_non_empty_lines(3)" -visible_working = true -line_regex = ['^[•◦]\s+Working \([^)]*esc to interrupt\)(?: · .*)?$'] -not = [{ contains = ["■ Conversation interrupted"] }] - -[[rules]] -id = "osc_title_idle" -state = "idle" -priority = 100 -region = "osc_title" -visible_idle = true -regex = ['\S'] -not = [ - { regex = ['(?:^| )[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏](?: |$)'] }, - { contains = ["Action Required"] }, -] diff --git a/website/agent-detection/cursor.toml b/website/agent-detection/cursor.toml deleted file mode 100644 index ee03e6db..00000000 --- a/website/agent-detection/cursor.toml +++ /dev/null @@ -1,57 +0,0 @@ -id = "cursor" -version = "2026.08.03.1" -min_engine_version = 1 -updated_at = "2026-08-03T01:08:04Z" -aliases = ["cursor-agent"] - -[[rules]] -id = "write_file_approval" -state = "blocked" -priority = 320 -region = "bottom_non_empty_lines(8)" -visible_blocker = true -contains = ["write to this file?", "proceed (y)"] -any = [ - { contains = ["reject & propose changes"] }, - { contains = ["esc or n or p"] }, - { contains = ["add write("] }, -] - -[[rules]] -id = "approval_prompt" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -any = [ - { contains = ["waiting for approval", "run this command?"], any = [{ contains = ["run (once) (y)"] }, { contains = ["skip (esc or n)"] }] }, - { contains = ["(y) (enter)"] }, - { line_regex = ['(?i)^\s*allow .*\(y\)'] }, - { contains = ["keep (n)"] }, - { contains = ["skip (esc or n)"] }, - { line_regex = ['(?i)^\s*(?:→\s*)?run .*\(y\)'] }, -] - -[[rules]] -id = "stop_hint_working" -state = "working" -priority = 100 -region = "bottom_non_empty_lines(6)" -visible_working = true -contains = ["ctrl+c to stop"] - -[[rules]] -id = "background_task_status_working" -state = "working" -priority = 95 -region = "bottom_non_empty_lines(5)" -visible_working = true -line_regex = ['(?i)\b[1-9][0-9]*\s+background\s+tasks?\b'] - -[[rules]] -id = "spinner_working" -state = "working" -priority = 90 -region = "bottom_non_empty_lines(8)" -visible_working = true -line_regex = ['^\s*(⬡|⬢|[\u2800-\u28FF]+)\s+\p{Alphabetic}+\w*ing\b'] diff --git a/website/agent-detection/devin.toml b/website/agent-detection/devin.toml deleted file mode 100644 index c9564f7c..00000000 --- a/website/agent-detection/devin.toml +++ /dev/null @@ -1,86 +0,0 @@ -id = "devin" -version = "2026.06.15.1" -min_engine_version = 1 -updated_at = "2026-06-15T00:00:00Z" -aliases = ["devin-cli", "devin cli"] - -[[rules]] -id = "workspace_trust_prompt" -state = "blocked" -priority = 300 -region = "bottom_non_empty_lines(8)" -visible_blocker = true -contains = [ - "do you trust the authors of this directory?", - "with untrusted content.", - "yes, trust ", -] - -[[rules]] -id = "permission_prompt" -state = "blocked" -priority = 290 -region = "bottom_non_empty_lines(8)" -visible_blocker = true -contains = ["approve once", "select", "confirm", "esc cancel"] - -[[rules]] -id = "running_tools_footer" -state = "working" -priority = 200 -region = "bottom_non_empty_lines(8)" -visible_working = true -contains = ["running tools", "esc to interrupt"] -not = [ - { contains = ["approve once", "esc cancel"] }, -] - -[[rules]] -id = "guide_while_working" -state = "working" -priority = 190 -region = "bottom_non_empty_lines(6)" -visible_working = true -contains = ["guide devin while it works"] -not = [ - { contains = ["approve once", "esc cancel"] }, -] - -[[rules]] -id = "tool_reading_timeout" -state = "working" -priority = 180 -region = "bottom_non_empty_lines(8)" -visible_working = true -contains = ["reading shell ", "timeout:"] -not = [ - { contains = ["approve once", "esc cancel"] }, -] - -[[rules]] -id = "welcome_prompt_footer" -state = "idle" -priority = 120 -region = "bottom_non_empty_lines(8)" -visible_idle = true -contains = ["ask devin to build", "features, fix bugs", "your code"] -line_regex = ['^\s*❭ Ask Devin to build'] -not = [ - { contains = ["approve once", "esc cancel"] }, - { contains = ["running tools", "esc to interrupt"] }, - { contains = ["guide devin while it works"] }, -] - -[[rules]] -id = "live_prompt_footer" -state = "idle" -priority = 100 -region = "bottom_non_empty_lines(6)" -visible_idle = true -contains = ["context:"] -line_regex = ['^\s*❭'] -not = [ - { contains = ["approve once", "esc cancel"] }, - { contains = ["running tools", "esc to interrupt"] }, - { contains = ["guide devin while it works"] }, -] diff --git a/website/agent-detection/droid.toml b/website/agent-detection/droid.toml deleted file mode 100644 index c41d71b4..00000000 --- a/website/agent-detection/droid.toml +++ /dev/null @@ -1,48 +0,0 @@ -id = "droid" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" - -[[rules]] -id = "execute_selection_blocker" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -contains = ["enter to select", "esc to cancel"] -any = [ - { contains = ["↑↓ to navigate"] }, - { contains = ["use ↑↓ to navigate"] }, -] -all = [ - { any = [{ contains = ["> yes, allow"] }, { contains = ["> no, cancel"] }] }, -] - -[[rules]] -id = "selection_menu_blocker" -state = "blocked" -priority = 290 -region = "bottom_non_empty_lines(8)" -visible_blocker = true -contains = ["enter select", "esc cancel"] -any = [ - { contains = ["↑/↓ navigate"] }, - { contains = ["↑↓ navigate"] }, -] - -[[rules]] -id = "spinner_stop_working" -state = "working" -priority = 110 -region = "whole_recent" -visible_working = true -contains = ["esc to stop"] -line_regex = ['^\s*[\u2800-\u28FF]'] - -[[rules]] -id = "stop_hint_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -contains = ["esc to stop"] diff --git a/website/agent-detection/gemini.toml b/website/agent-detection/gemini.toml deleted file mode 100644 index 9d7a28e1..00000000 --- a/website/agent-detection/gemini.toml +++ /dev/null @@ -1,25 +0,0 @@ -id = "gemini" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" - -[[rules]] -id = "apply_or_allow_change" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -any = [ - { contains = ["│ Apply this change"] }, - { contains = ["│ Allow execution"] }, - { all = [{ contains = ["yes"] }, { any = [{ contains = ["waiting for user confirmation"] }, { contains = ["│ Do you want to proceed"] }, { contains = ["do you want to proceed?"] }] }] }, - { line_regex = ['(?i)^\s*❯.*(yes|allow)'] }, -] - -[[rules]] -id = "esc_cancel_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -contains = ["esc to cancel"] diff --git a/website/agent-detection/github-copilot.toml b/website/agent-detection/github-copilot.toml deleted file mode 100644 index 57fafdd8..00000000 --- a/website/agent-detection/github-copilot.toml +++ /dev/null @@ -1,45 +0,0 @@ -id = "copilot" -version = "2026.08.29.1" -min_engine_version = 1 -updated_at = "2026-08-29T00:00:00Z" -aliases = ["github-copilot", "ghcs"] - -[[rules]] -id = "selection_blocker" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -all = [ - { any = [ - { contains = ["esc to cancel"] }, - { contains = ["esc cancel"] }, - ] }, - { any = [ - { contains = ["enter to select"] }, - { contains = ["enter to confirm"] }, - { contains = ["enter to submit"] }, - { contains = ["enter accept"] }, - ] }, -] - -[[rules]] -id = "background_agents_working" -state = "working" -priority = 110 -region = "bottom_non_empty_lines(6)" -visible_working = true -line_regex = ['^\s*◎\s+Waiting for background agents(?:\s|·|$)'] - -[[rules]] -id = "working_cancel_hint" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -any = [ - { contains = ["esc to cancel"] }, - { contains = ["esc cancel"] }, - { contains = ["esc again to cancel"] }, - { contains = ["esc interrupt"] } -] diff --git a/website/agent-detection/grok.toml b/website/agent-detection/grok.toml deleted file mode 100644 index 996cf377..00000000 --- a/website/agent-detection/grok.toml +++ /dev/null @@ -1,153 +0,0 @@ -id = "grok" -version = "2026.07.16.1" -min_engine_version = 2 -updated_at = "2026-07-16T00:00:00Z" -aliases = ["grok-build"] - -# Evidence: Grok Build 0.2.101 source and live pane reads. -# -# Grok emits OSC 0 titles by default. Idle is "grok" or -# "<session> - grok". During a turn, the configured title gains a braille -# spinner and activity text. Permission prompts add "⚠ Action Required"; -# that prefix blinks while the terminal is unfocused, so visible blocker -# rules outrank the generic non-idle title rule. -# -# Grok also emits OSC 9;4 progress on supported terminals. Herdr retains the -# payload after "9;": "4;1;-1" while busy and "4;0;0" when idle. -# -# Working turns render one live status line directly above the prompt box: -# "⠧ Waiting on subagent… 2.8s 13s ⇣29.7k [stop]" -# "⠴ Explore /tmp/… + 1 more… 5.6s 19s ⇣29.7k [stop]" -# with a braille spinner and a trailing [stop] chip, plus an Esc:cancel -# footer hint. Permission prompts and ask-user-question dialogs replace the -# spinner with "◆" and draw a "┃"-guttered option list: -# "┃ 2 (○) Yes, proceed" -# "┃ z (○) Type your answer here" -# with footer hints "1/3:select │ Ctrl+o:yolo │ Ctrl+c:cancel" (permission) -# or "Esc:unselect │ Tab:scrollback │ Shift+x:dismiss" (question dialog). -# Idle footers end with "Ctrl+.:shortcuts" and never contain "Esc:cancel". -# The startup splash draws its logo with braille characters, so working -# rules must anchor on the [stop] chip, not on a bare spinner glyph. - -[[rules]] -id = "osc_title_blocked" -state = "blocked" -priority = 1300 -region = "osc_title" -visible_blocker = true -contains = ["Action Required"] - -[[rules]] -id = "option_dialog_blocked" -state = "blocked" -priority = 1200 -region = "whole_recent" -visible_blocker = true -line_regex = ['^\s*┃\s+[0-9a-z]+\s+\([●○]\)\s'] - -[[rules]] -id = "permission_hints_blocked" -state = "blocked" -priority = 1190 -region = "bottom_non_empty_lines(2)" -visible_blocker = true -contains = [":select", "ctrl+o:yolo", "ctrl+c:cancel"] - -[[rules]] -id = "question_dialog_hints_blocked" -state = "blocked" -priority = 1185 -region = "bottom_non_empty_lines(2)" -visible_blocker = true -contains = ["tab:scrollback", "shift+x:dismiss"] - -# Pre-0.2.x permission UI kept for older Grok Build releases. -[[rules]] -id = "permission_scope_selector" -state = "blocked" -priority = 1180 -region = "whole_recent" -visible_blocker = true -contains = ["yes, proceed", "no, reject"] -any = [ - { contains = ["use ← → to choose permission whitelist scope"] }, - { contains = ["←/→:scope"] }, -] - -[[rules]] -id = "osc_progress_working" -state = "working" -priority = 1150 -region = "osc_progress" -visible_working = true -regex = ['^4;1;-1$'] - -[[rules]] -id = "osc_title_idle" -state = "idle" -priority = 1100 -region = "osc_title" -visible_idle = true -regex = ['(?:^| - )grok$'] -not = [ - { regex = ['[\x{2800}-\x{28FF}]'] }, -] - -# After known idle titles are excluded, any other non-empty Grok title is -# active. OSC progress remains authoritative when a custom title omits the -# spinner but the terminal supports progress reporting. -[[rules]] -id = "osc_title_working" -state = "working" -priority = 1000 -region = "osc_title" -visible_working = true -regex = ['\S'] - -[[rules]] -id = "osc_progress_idle" -state = "idle" -priority = 950 -region = "osc_progress" -visible_idle = true -regex = ['^4;0;0$'] - -[[rules]] -id = "spinner_status_working" -state = "working" -priority = 200 -region = "whole_recent" -visible_working = true -line_regex = ['^\s*[\x{2801}-\x{28FF}]\s.*\[stop\]\s*$'] - -[[rules]] -id = "esc_cancel_hints_working" -state = "working" -priority = 190 -region = "bottom_non_empty_lines(2)" -visible_working = true -contains = ["esc:cancel", "ctrl+.:shortcuts"] - -# Pre-0.2.x working chrome kept for older Grok Build releases. -[[rules]] -id = "waiting_tool_working" -state = "working" -priority = 120 -region = "whole_recent" -visible_working = true -any = [ - { all = [{ contains = ["ctrl+c:cancel", "ctrl+enter:interject"] }, { contains = ["waiting"] }] }, - { line_regex = ['^\s*[\x{2801}-\x{28FF}]\s+(Run|Read|Search|List)\b'] }, -] - -[[rules]] -id = "prompt_hints_idle" -state = "idle" -priority = 100 -region = "bottom_non_empty_lines(2)" -visible_idle = true -contains = ["ctrl+.:shortcuts"] -not = [ - { contains = ["esc:cancel"] }, - { contains = ["ctrl+c:cancel"] }, -] diff --git a/website/agent-detection/hermes.toml b/website/agent-detection/hermes.toml deleted file mode 100644 index 17542184..00000000 --- a/website/agent-detection/hermes.toml +++ /dev/null @@ -1,102 +0,0 @@ -id = "hermes" -version = "2026.07.24.1" -min_engine_version = 2 -updated_at = "2026-07-24T19:12:54Z" -aliases = ["hermes-agent"] - -[[rules]] -id = "osc_title_blocked" -state = "blocked" -priority = 1100 -region = "osc_title" -visible_blocker = true -regex = ['^⚠[\u{fe0e}\u{fe0f}]?(?:\s|$)'] - -[[rules]] -id = "osc_title_working" -state = "working" -priority = 1050 -region = "osc_title" -visible_working = true -regex = ['^⏳[\u{fe0e}\u{fe0f}]?(?:\s|$)'] - -[[rules]] -id = "dangerous_command_approval" -state = "blocked" -priority = 900 -region = "bottom_non_empty_lines(14)" -visible_blocker = true -any = [ - { contains = ["dangerous"] }, - { contains = ["approval"] }, - { contains = ["allow once", "deny"] }, - { line_regex = ['(?i)^\s*[▸>]?\s*1\.\s*allow'] }, -] -all = [ - { any = [{ contains = ["enter confirm"] }, { contains = ["enter to confirm"] }, { contains = ["↑/↓ to select"] }, { contains = ["show full command"] }] }, -] - -[[rules]] -id = "clarification_prompt" -state = "blocked" -priority = 900 -region = "bottom_non_empty_lines(14)" -visible_blocker = true -any = [ - { contains = ["hermes needs your"] }, - { line_regex = ['^\s*ask\s+\S'] }, - { contains = ["type your answer"] }, -] -all = [ - { any = [{ contains = ["enter confirm"] }, { contains = ["enter to confirm"] }, { contains = ["enter send"] }, { contains = ["press enter"] }, { contains = ["↑/↓ select"] }, { contains = ["↑/↓ to select"] }, { contains = ["other (type"] }] }, -] - -[[rules]] -id = "credential_prompt" -state = "blocked" -priority = 900 -region = "bottom_non_empty_lines(14)" -visible_blocker = true -any = [ - { contains = ["sudo password"] }, - { contains = ["skill setup"] }, - { contains = ["🔑", "for "] }, -] - -[[rules]] -id = "confirmation_prompt" -state = "blocked" -priority = 900 -region = "bottom_non_empty_lines(14)" -visible_blocker = true -all = [ - { any = [{ contains = ["approve once", "cancel"] }, { contains = ["start a new session", "keep going"] }] }, - { any = [{ contains = ["enter to confirm"] }, { contains = ["enter confirm"] }, { contains = ["type 1/2/3"] }, { contains = ["y/n quick"] }] }, -] - -[[rules]] -id = "interrupt_status_working" -state = "working" -priority = 950 -region = "bottom_non_empty_lines(5)" -visible_working = true -any = [ - { contains = ["msg=interrupt"] }, - { contains = ["ctrl+c to interrupt"] }, -] - -[[rules]] -id = "classic_cancel_working" -state = "working" -priority = 500 -region = "bottom_non_empty_lines(5)" -visible_working = true -contains = ["ctrl+c cancel"] - -[[rules]] -id = "osc_title_idle" -state = "idle" -priority = 100 -region = "osc_title" -visible_idle = true -regex = ['^✓[\u{fe0e}\u{fe0f}]?(?:\s|$)'] diff --git a/website/agent-detection/index.toml b/website/agent-detection/index.toml deleted file mode 100644 index f44a8306..00000000 --- a/website/agent-detection/index.toml +++ /dev/null @@ -1,81 +0,0 @@ -schema_version = 1 - -[[agents]] -id = "amp" -path = "amp.toml" - -[[agents]] -id = "agy" -path = "antigravity.toml" - -[[agents]] -id = "claude" -path = "claude.toml" - -[[agents]] -id = "cline" -path = "cline.toml" - -[[agents]] -id = "codex" -path = "codex.toml" - -[[agents]] -id = "cursor" -path = "cursor.toml" - -[[agents]] -id = "devin" -path = "devin.toml" - -[[agents]] -id = "droid" -path = "droid.toml" - -[[agents]] -id = "gemini" -path = "gemini.toml" - -[[agents]] -id = "grok" -path = "grok.toml" - -[[agents]] -id = "hermes" -path = "hermes.toml" - -[[agents]] -id = "kilo" -path = "kilo.toml" - -[[agents]] -id = "kimi" -path = "kimi.toml" - -[[agents]] -id = "kiro" -path = "kiro.toml" - -[[agents]] -id = "maki" -path = "maki.toml" - -[[agents]] -id = "opencode" -path = "opencode.toml" - -[[agents]] -id = "pi" -path = "pi.toml" - -[[agents]] -id = "qodercli" -path = "qodercli.toml" - -[[agents]] -id = "qwen" -path = "qwen.toml" - -[[agents]] -id = "copilot" -path = "github-copilot.toml" diff --git a/website/agent-detection/kilo.toml b/website/agent-detection/kilo.toml deleted file mode 100644 index 4ef004e1..00000000 --- a/website/agent-detection/kilo.toml +++ /dev/null @@ -1,24 +0,0 @@ -id = "kilo" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" -aliases = ["kilo-code", "kilo code", "herdr:kilo"] - -[[rules]] -id = "opencode_permission" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -any = [ - { contains = ["△ Permission required"] }, - { contains = ["esc dismiss"], any = [{ contains = ["enter confirm"] }, { contains = ["enter submit"] }, { contains = ["enter toggle"] }], all = [{ any = [{ contains = ["↑↓ select"] }, { contains = ["⇆ tab"] }] }] }, -] - -[[rules]] -id = "esc_interrupt_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -contains = ["esc interrupt"] diff --git a/website/agent-detection/kimi.toml b/website/agent-detection/kimi.toml deleted file mode 100644 index b4d0100f..00000000 --- a/website/agent-detection/kimi.toml +++ /dev/null @@ -1,77 +0,0 @@ -id = "kimi" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" -aliases = ["kimi-code", "kimi code"] - -[[rules]] -id = "current_approval_panel" -state = "blocked" -priority = 400 -region = "whole_recent" -visible_blocker = true -contains = ["↵ confirm"] -any = [ - { contains = ["run this command?"] }, - { contains = ["write this file?"] }, - { contains = ["apply these edits?"] }, - { contains = ["stop this task?"] }, - { contains = ["ready to build with this plan?"] }, - { line_regex = ['(?i)^\s*▶?\s*approve .*\?$'] }, -] -all = [ - { contains = [" choose"] }, - { any = [{ contains = ["approve"] }, { contains = ["reject"] }, { contains = ["revise"] }] }, -] - -[[rules]] -id = "question_panel" -state = "blocked" -priority = 390 -region = "whole_recent" -visible_blocker = true -contains = ["↑↓ select", "esc cancel"] -line_regex = ['^\s*question\s*$', '^\s*\? '] -any = [ - { contains = ["↵ choose"] }, - { contains = ["↵ toggle"] }, - { contains = ["↵ save"] }, -] - -[[rules]] -id = "legacy_approval_panel" -state = "blocked" -priority = 300 -region = "whole_recent" -contains = ["requesting approval", "reject"] -any = [ - { contains = ["approve once"] }, - { contains = ["approve for this session"] }, -] -all = [ - { any = [{ contains = ["1/2/3/4 choose"] }, { contains = ["↵ confirm"] }] }, -] - -[[rules]] -id = "background_agent_status_working" -state = "working" -priority = 120 -region = "bottom_non_empty_lines(3)" -visible_working = true -line_regex = ['(?i)\bkimi[-\w.]*\s+thinking\b.*\[[1-9][0-9]*\s+agents?\s+running\]'] - -[[rules]] -id = "moon_spinner_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -line_regex = ['^\s*(🌕|🌖|🌗|🌘|🌑|🌒|🌓|🌔)\s*$'] - -[[rules]] -id = "braille_spinner_working" -state = "working" -priority = 90 -region = "whole_recent" -visible_working = true -line_regex = ['(?i)^\s*[\u2800-\u28FF]+\s*(thinking\.\.\.|working\.\.\.|using )'] diff --git a/website/agent-detection/kiro.toml b/website/agent-detection/kiro.toml deleted file mode 100644 index 59ac0a06..00000000 --- a/website/agent-detection/kiro.toml +++ /dev/null @@ -1,63 +0,0 @@ -id = "kiro" -version = "2026.08.01.1" -min_engine_version = 1 -updated_at = "2026-08-01T00:00:00Z" -aliases = ["kiro-cli"] - -[[rules]] -id = "tool_approval" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -contains = ["requires approval"] -any = [ - { contains = ["yes, single permission"] }, - { contains = ["trust, always allow"] }, - { contains = ["no (tab to edit)"] }, - { contains = ["esc to close"] }, -] - -[[rules]] -id = "subagent_approval" -state = "blocked" -priority = 290 -region = "whole_recent" -visible_blocker = true -contains = ["pending from subagents"] -any = [ - { contains = ["tool approval"] }, - { contains = ["tool approvals"] }, -] -all = [ - { any = [{ contains = ["approve all pending"] }, { contains = ["configure individually"] }, { contains = ["exit (cancel subagents)"] }] }, -] - -[[rules]] -id = "prompt_idle" -state = "idle" -priority = 200 -region = "bottom_non_empty_lines(5)" -visible_idle = true -contains = ["ask a question or describe a task", "/copy to clipboard"] -not = [ - { contains = ["kiro is working"] }, - { contains = ["esc to cancel"] }, -] - -[[rules]] -id = "kiro_working_marker" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -contains = ["kiro is working"] - -[[rules]] -id = "tool_spinner_working" -state = "working" -priority = 90 -region = "whole_recent" -visible_working = true -contains = ["esc to cancel"] -line_regex = ['^\s*(◔|◑|◕|●)\s+\p{Alphabetic}'] diff --git a/website/agent-detection/maki.toml b/website/agent-detection/maki.toml deleted file mode 100644 index 5c58404a..00000000 --- a/website/agent-detection/maki.toml +++ /dev/null @@ -1,68 +0,0 @@ -id = "maki" -version = "2026.07.09.2" -min_engine_version = 1 -updated_at = "2026-07-09T00:00:00Z" - -# Maki renders a persistent one-line status bar on the bottom row. It starts -# with the mode label "[BUILD]", "[PLAN]", or "[BASH]" when idle and gets a -# leading braille spinner cell while the agent is streaming. Permission -# requests and the plan-complete form replace the input box above the status -# bar. Maki does not set OSC title or OSC 9;4 progress. - -[[rules]] -id = "permission_prompt" -state = "blocked" -priority = 980 -region = "whole_recent" -visible_blocker = true -contains = ["permission required"] -any = [ - { contains = ["y allow", "n deny"] }, - { contains = ["confirm allow"] }, - { contains = ["confirm deny"] }, - { contains = ["enter deny", "esc cancel"] }, -] - -[[rules]] -id = "plan_complete_form" -state = "blocked" -priority = 970 -region = "whole_recent" -visible_blocker = true -contains = ["plan complete", "enter confirm"] -any = [ - { contains = ["space toggle parallel"] }, - { contains = ["edit plan"] }, -] - -[[rules]] -id = "status_bar_spinner_working" -state = "working" -priority = 900 -region = "bottom_non_empty_lines(1)" -visible_working = true -line_regex = ['^( [\x{2800}-\x{28FF}]){1,2} \[(BUILD|PLAN|BASH)\]'] - -[[rules]] -id = "status_bar_idle" -state = "idle" -priority = 850 -region = "bottom_non_empty_lines(1)" -visible_idle = true -line_regex = ['^ \[(BUILD|PLAN|BASH)\]'] - -# On narrow panes the right side of the status bar overwrites the mode label, -# so fall back to the prompt chevron above the input box border. The not-gates -# keep this from matching the streaming placeholder or a status bar that still -# shows the spinner. -[[rules]] -id = "prompt_box_idle" -state = "idle" -priority = 840 -region = "bottom_non_empty_lines(3)" -visible_idle = true -line_regex = ['^❯ '] -not = [ - { contains = ["queue another prompt"] }, - { line_regex = ['^( [\x{2800}-\x{28FF}]){1,2} '] }, -] diff --git a/website/agent-detection/opencode.toml b/website/agent-detection/opencode.toml deleted file mode 100644 index 52452383..00000000 --- a/website/agent-detection/opencode.toml +++ /dev/null @@ -1,37 +0,0 @@ -id = "opencode" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" -aliases = ["open-code", "herdr:opencode"] - -[[rules]] -id = "permission_required" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -any = [ - { contains = ["△ Permission required"] }, - { contains = ["esc dismiss"], any = [{ contains = ["enter confirm"] }, { contains = ["enter submit"] }, { contains = ["enter toggle"] }], all = [{ any = [{ contains = ["↑↓ select"] }, { contains = ["⇆ tab"] }] }] }, -] - -[[rules]] -id = "interrupt_hint_working" -state = "working" -priority = 110 -region = "whole_recent" -visible_working = true -any = [ - { contains = ["esc to interrupt"] }, - { contains = ["ctrl+c to interrupt"] }, - { contains = ["press esc to interrupt"] }, - { line_regex = ['(?i).*opencode.*esc (again to )?interrupt'] }, -] - -[[rules]] -id = "progress_bar_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -regex = ['(■|⬝){4,}'] diff --git a/website/agent-detection/pi.toml b/website/agent-detection/pi.toml deleted file mode 100644 index a58d30e9..00000000 --- a/website/agent-detection/pi.toml +++ /dev/null @@ -1,13 +0,0 @@ -id = "pi" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" -aliases = ["herdr:pi"] - -[[rules]] -id = "working_literal" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -contains = ["Working..."] diff --git a/website/agent-detection/qodercli.toml b/website/agent-detection/qodercli.toml deleted file mode 100644 index 51ca805e..00000000 --- a/website/agent-detection/qodercli.toml +++ /dev/null @@ -1,38 +0,0 @@ -id = "qodercli" -version = "2026.06.10.1" -min_engine_version = 1 -updated_at = "2026-06-10T00:00:00Z" -aliases = ["qoderclicn", "qoder", "qodercn"] - -[[rules]] -id = "confirmation_or_input_blocker" -state = "blocked" -priority = 300 -region = "whole_recent" -visible_blocker = true -any = [ - { contains = ["waiting for user confirmation"], any = [{ contains = ["yes"] }, { contains = ["no"] }, { contains = ["allow"] }, { contains = ["reject"] }] }, - { contains = ["awaiting approval"], any = [{ contains = ["allow"] }, { contains = ["reject"] }] }, - { contains = ["permission required"] }, - { contains = ["allow once or always?"] }, - { contains = ["asking user"] }, - { contains = ["enter your response"] }, - { contains = ["review your answers:"] }, - { contains = ["shell awaiting input"] }, -] - -[[rules]] -id = "cancel_hint_working" -state = "working" -priority = 100 -region = "whole_recent" -visible_working = true -contains = ["(esc to cancel,"] - -[[rules]] -id = "spinner_working" -state = "working" -priority = 90 -region = "whole_recent" -visible_working = true -line_regex = ['^\s*[\u2800-\u28FF]\s+.*\p{Alphabetic}'] diff --git a/website/agent-detection/qwen.toml b/website/agent-detection/qwen.toml deleted file mode 100644 index bbed2371..00000000 --- a/website/agent-detection/qwen.toml +++ /dev/null @@ -1,119 +0,0 @@ -id = "qwen" -version = "2026.08.14.1" -min_engine_version = 2 -updated_at = "2026-08-14T00:00:00Z" -aliases = ["qwen-code", "qwen code"] - -# Qwen Code keeps its composer visible while responding, so the prompt box is -# not idle evidence by itself. Its status-prefixed terminal titles are the -# primary locale-independent signals when ui.showStatusInTitle is enabled. -# Exact screen fallbacks cover built-in locales and narrow terminals. OSC 9;4 -# is supplemental because Qwen emits it only while a tool is executing and -# only in terminals that advertise progress support. - -[[rules]] -id = "osc_title_blocked" -state = "blocked" -priority = 1200 -region = "osc_title" -visible_blocker = true -regex = ['^\x{2733}\x{FE0E}? '] - -[[rules]] -id = "osc_title_working" -state = "working" -priority = 1100 -region = "osc_title" -visible_working = true -regex = ['^\x{25D0}\x{FE0E}? '] - -[[rules]] -id = "waiting_for_confirmation" -state = "blocked" -priority = 1000 -region = "bottom_non_empty_lines(20)" -visible_blocker = true -line_regex = ['^\s*⠏\s+.*\.\.\.\s*$'] -any = [ - { contains = ["Waiting for user confirmation..."] }, - { contains = ["等待用户确认..."] }, - { contains = ["等待用戶確認..."] }, - { contains = ["Warten auf Benutzerbestätigung..."] }, - { contains = ["En attente de la confirmation de l'utilisateur..."] }, - { contains = ["ユーザーの確認を待っています..."] }, - { contains = ["Aguardando confirmação do usuário..."] }, - { contains = ["Ожидание подтверждения от пользователя..."] }, - { contains = ["Esperant la confirmació de l'usuari..."] }, -] - -[[rules]] -id = "tool_confirmation" -state = "blocked" -priority = 990 -region = "bottom_non_empty_lines(20)" -visible_blocker = true -contains = ["yes, allow once"] -any = [ - { contains = ["apply this change?"] }, - { contains = ["allow execution of:"] }, - { contains = ["allow execution of mcp tool"] }, - { contains = ["do you want to proceed?"] }, - { contains = ["shell command execution"] }, -] - -[[rules]] -id = "question_dialog" -state = "blocked" -priority = 980 -region = "bottom_non_empty_lines(20)" -visible_blocker = true -line_regex = [ - '^\s*[❯›]\s*(?:\[(?: |✓)\]\s*)?\d+\.\s+', - '^\s*↑/↓\s*:.*(?:Enter|Return)\s*:', -] - -[[rules]] -id = "folder_trust_dialog" -state = "blocked" -priority = 970 -region = "bottom_non_empty_lines(20)" -visible_blocker = true -contains = ["do you trust this folder?", "trust folder (", "don't trust (esc)"] - -[[rules]] -id = "cancel_hint_working" -state = "working" -priority = 900 -region = "bottom_non_empty_lines(8)" -visible_working = true -line_regex = ['^\s*(?:[⠁-⣿]|\.{1,2})\s+.*\(\d+(?:m(?:\s+\d+s)?|s).*\s·\sesc to cancel\)\s*$'] - -[[rules]] -id = "narrow_cancel_hint_working" -state = "working" -priority = 890 -region = "bottom_non_empty_lines(8)" -visible_working = true -line_regex = ['^\s*\(\d+(?:m(?:\s+\d+s)?|s)\s·\sesc to cancel\)\s*$'] - -[[rules]] -id = "osc_tool_progress_working" -state = "working" -priority = 850 -region = "osc_progress" -visible_working = true -regex = ['^4;3(?:;|$)'] - -[[rules]] -id = "composer_idle" -state = "idle" -priority = 100 -region = "bottom_non_empty_lines(30)" -visible_idle = true -line_regex = ['^\s*>\s*(?:type\s*)?.*$'] -any = [ - { contains = ["type your message"] }, - { contains = ["your message or @path/to/file"] }, - { contains = ["@path/to/file"] }, - { contains = ["type", "mes", "sage", "@pat", "h/to", "/fil"] }, -] diff --git a/website/agent-guide.md b/website/agent-guide.md deleted file mode 100644 index b542dd94..00000000 --- a/website/agent-guide.md +++ /dev/null @@ -1,100 +0,0 @@ -# Herdr agent guide - -Use this guide to help a human understand, set up, or troubleshoot Herdr. It covers Herdr's concept model, setup path, and diagnosis recipes. Canonical documentation lives at https://herdr.dev/docs/. Point the human there for more detail, and verify any command you are unsure about against those pages instead of guessing. - -If you are running *inside* a Herdr pane (the environment variable `HERDR_ENV=1` is set), Herdr also ships a skill file that teaches you to control Herdr through the `herdr` CLI: https://raw.githubusercontent.com/herdrdev/herdr/master/skills/herdr/SKILL.md. That file teaches you to operate Herdr; this one teaches you to guide a human. - -## What Herdr is - -Herdr is a terminal workspace manager for AI coding agents. Like tmux, it is a multiplexer: a background server owns real terminal processes, and clients attach to render them. Panes keep running when the human detaches, closes the terminal, or disconnects SSH. - -Unlike tmux, Herdr is mouse-first and agent-aware. The whole UI is clickable — panes, tabs, workspaces, split borders, right-click menus. Herdr detects coding agents running inside panes and shows each one's state in a sidebar, so the human can see across all their projects which agent is `working`, which is `blocked` waiting for input, and which is `done`. A CLI and a local socket API let scripts and agents drive Herdr programmatically. - -## Concept model - -Teach these in this order: - -- **Session** — a persistent background server namespace. Running `herdr` attaches to the default session. Named sessions (`herdr session attach work`) are fully separate runtime namespaces; most people only need the default. -- **Workspace** — the project-level container. One per repo, task, or investigation. Owns tabs and panes. The sidebar rolls agent states up per workspace. -- **Tab** — a layout inside a workspace, for separating views like `agents`, `logs`, `server`. -- **Pane** — a real terminal. Splittable right or down. Survives client detach. -- **Agent** — a process Herdr recognizes inside a pane. States: `working`, `blocked`, `done`, `idle`, `unknown`. -- **Modes** — terminal mode sends keys to the focused pane; prefix mode (`ctrl+b`, then one action key) sends one command to Herdr; navigate mode is a persistent navigation surface. - -Full concepts page: https://herdr.dev/docs/concepts/ - -## Install - -Linux and macOS: - -```bash -curl -fsSL https://herdr.dev/install.sh | sh -herdr -``` - -Windows PowerShell: - -```powershell -powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex" -herdr -``` - -If endpoint security blocks that fileless PowerShell command, use Command Prompt: - -```cmd -curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd -herdr -``` - -Homebrew, mise, and Nix installs, verification, and manual downloads: https://herdr.dev/docs/install/. Direct installs use the stable channel by default and update with `herdr update`; preview is opt-in. Package-manager installs update through that package manager. Check the version with `herdr --version`. - -## First-run walkthrough - -Check your environment first. If `HERDR_ENV=1` is set, you are already running inside a Herdr pane. The human is already attached, so skip step 1 and never tell them to run `herdr` from your pane; Herdr blocks nested launches by design. Start with step 2, and consider the skill file below. - -Walk the human through this sequence: - -1. `cd` into a project and run `herdr`. It launches or attaches to the default background session and creates a workspace automatically. First run shows an onboarding flow. -2. Start their coding agent in the pane — `claude`, `codex`, or any supported agent (full list: https://herdr.dev/docs/agents/). Herdr detects it automatically; the sidebar shows its state. Install the matching integration when available. Depending on the agent, it provides lifecycle state, native session restore, or both. For example, `herdr integration install claude` adds native session restore, while Claude's state still comes from screen detection. -3. Start with the mouse: click panes and tabs to focus, drag split borders, right-click for menus, drag-select to copy. No keybindings are required to use Herdr. -4. Split panes: right-click menu, or `prefix+v` (right) / `prefix+minus` (down). New tab: `prefix+c`. -5. Detach with `prefix+q` (press `ctrl+b`, release, press `q`) or close the terminal window. Everything keeps running. Reattach later with `herdr`. -6. To actually stop everything: `herdr server stop`. - -## The keyboard story - -New users do not need to learn keybindings; the mouse covers everything. When the human wants keyboard control: - -- The prefix key is `ctrl+b` by default. `prefix+?` shows every active binding live. -- The guided keyboard page covers the prefix, the bindings to learn first, and a vetted prefix-free setup using `ctrl+alt` chords: https://herdr.dev/docs/keyboard/. Recommend it over improvising. -- Every binding, including the prefix itself, is configurable under `[keys]` in the config file. -- If a direct chord does nothing, the OS or the outer terminal consumed it before Herdr could see it. The keyboard page explains which chords are safe and why. - -## Install the Herdr skill into yourself - -Herdr ships `skills/herdr/SKILL.md` (https://raw.githubusercontent.com/herdrdev/herdr/master/skills/herdr/SKILL.md), which teaches a coding agent to control Herdr from inside a pane: splitting panes, running commands without stealing focus, reading output, and waiting on other agents. - -Once the human is set up, offer to install it for your coding agent so future sessions can control Herdr directly. For agents supported by the open skills CLI, use `npx skills add herdrdev/herdr --skill herdr -g`. For agents without a skill system, add the GitHub copy above to their global custom instructions. Ask the human before writing to their config locations, and use the GitHub copy above as the source of truth. - -## Configuration - -- Config file: `~/.config/herdr/config.toml` on Linux and macOS; `%APPDATA%\herdr\config.toml` on Windows. Herdr works without one. -- Print the full default config: `herdr --default-config`. -- Apply edits to a running server: `herdr server reload-config` (or the global menu → reload config). -- Main areas: `[keys]` keybindings, `[theme]` themes, `[ui]` sidebar and UI behavior, `[terminal]` shell defaults, `[update]` channel. -- Full reference: https://herdr.dev/docs/configuration/ - -## Diagnosis recipes - -- **Agent not detected or wrong state:** Run `herdr agent list` to see what Herdr sees and `herdr agent explain <target> --json` to see why the detector classified a pane that way. Integrations can provide lifecycle state, native session restore, or both; check `herdr integration status` and the agent support table before assuming an integration replaces screen detection. Details: https://herdr.dev/docs/agents/ and https://herdr.dev/docs/integrations/ -- **A keybinding does nothing:** the outer terminal or desktop environment owns that chord. Point the human to https://herdr.dev/docs/keyboard/ to pick a safe one or free the chord in their terminal settings. -- **Something looks wrong at startup or with the socket API:** Default-session logs live in `~/.config/herdr/` on Linux and macOS and `%APPDATA%\herdr\` on Windows. Named-session logs live under `sessions/<name>/` inside that directory. `herdr status`, `herdr status server`, and `herdr status client` summarize the runtime. -- **Remote use:** SSH to the machine and run `herdr` there (works like tmux), or attach as a thin local client with `herdr --remote <host>`. Trade-offs: https://herdr.dev/docs/how-to-work/ -- **What survives a detach, restart, or update:** https://herdr.dev/docs/session-state/ - -## Rules for you - -- Do not invent keybindings, config keys, or CLI flags. The ones in this file are accurate as of writing; for anything else, read the linked docs page first. -- Teach mouse before keyboard for humans new to multiplexers. -- Herdr is not tmux: do not give tmux commands, tmux config syntax, or `.tmux.conf` advice for Herdr questions. -- For automation, scripting, or controlling Herdr from code, point to the CLI reference (https://herdr.dev/docs/cli-reference/) and socket API (https://herdr.dev/docs/socket-api/). 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 Binary files differdeleted file mode 100644 index 7a2f42b4..00000000 --- a/website/assets/agent-icons/droid.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 83c47737..00000000 --- a/website/assets/author-can.jpeg +++ /dev/null diff --git a/website/assets/favicon.png b/website/assets/favicon.png Binary files differdeleted file mode 100644 index a7720d48..00000000 --- a/website/assets/favicon.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 059ca4e7..00000000 --- a/website/assets/jbm.woff2 +++ /dev/null diff --git a/website/assets/logo.png b/website/assets/logo.png Binary files differdeleted file mode 100644 index 9c2e60c1..00000000 --- a/website/assets/logo.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 1908bcc0..00000000 --- a/website/assets/mobile-agent-session-v2.jpeg +++ /dev/null diff --git a/website/assets/mobile-switch-menu-v2.jpeg b/website/assets/mobile-switch-menu-v2.jpeg Binary files differdeleted file mode 100644 index 2901668d..00000000 --- a/website/assets/mobile-switch-menu-v2.jpeg +++ /dev/null diff --git a/website/assets/og-blog-coding-agents-runtimes.png b/website/assets/og-blog-coding-agents-runtimes.png Binary files differdeleted file mode 100644 index a8c1ee2f..00000000 --- a/website/assets/og-blog-coding-agents-runtimes.png +++ /dev/null diff --git a/website/assets/og-blog-frames-v1.png b/website/assets/og-blog-frames-v1.png Binary files differdeleted file mode 100644 index 9916587f..00000000 --- a/website/assets/og-blog-frames-v1.png +++ /dev/null diff --git a/website/assets/og-blog-live-updates.png b/website/assets/og-blog-live-updates.png Binary files differdeleted file mode 100644 index 80bccd4b..00000000 --- a/website/assets/og-blog-live-updates.png +++ /dev/null diff --git a/website/assets/og-blog-yc-v1.png b/website/assets/og-blog-yc-v1.png Binary files differdeleted file mode 100644 index 65817ff2..00000000 --- a/website/assets/og-blog-yc-v1.png +++ /dev/null diff --git a/website/assets/og-card-v8.png b/website/assets/og-card-v8.png Binary files differdeleted file mode 100644 index d9f85a30..00000000 --- a/website/assets/og-card-v8.png +++ /dev/null diff --git a/website/assets/og-card-v9.png b/website/assets/og-card-v9.png Binary files differdeleted file mode 100644 index 0a2d8b74..00000000 --- a/website/assets/og-card-v9.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index d33d0650..00000000 --- a/website/assets/releases/v0.6.3/session-navigator.mp4 +++ /dev/null diff --git a/website/assets/where-do-agents-run-while-you-sleep.png b/website/assets/where-do-agents-run-while-you-sleep.png Binary files differdeleted file mode 100644 index 45c98ad9..00000000 --- a/website/assets/where-do-agents-run-while-you-sleep.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index fe1d81c0..00000000 --- a/website/favicon.ico +++ /dev/null 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 — <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"> · index.html — swap ✻ for the real ▐▛███▜▌ mark, bump the version</div> - <div class="dim"> · 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"> <span class="cc-cyan">~/Projects/herdr/website</span><span class="cc-gy"> > </span><span class="cc-yellow">master *</span><span class="green"> ↑1</span><span class="cc-gy"> > ctx ──────── </span><span class="green">3%</span><span class="cc-gy"> 31k/1M</span></div> - <div class="cc-status"> <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 <span>http://localhost:4321/</span></div> - <div class="dim"> Network 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> 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%) 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"> 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"> └ Read jobs/backfill_events.py</div> - <br /> - <div><span class="cx-bullet">•</span> <b>Ran</b></div> - <div class="dim"> └ uv run pytest tests/test_backfill.py</div> - <div class="dim"> └ 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. <b class="arw">→</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 · 4 agents · 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. <b class="arw">→</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. <b class="arw">→</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. <b class="arw">→</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? <b class="arw">→</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> — <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/install.cmd b/website/install.cmd deleted file mode 100644 index 325e3b38..00000000 --- a/website/install.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -setlocal - -set "INSTALLER_URL=https://herdr.dev/install.ps1" -set "CURL_PROTOCOL=--proto =https --tlsv1.2" -if defined HERDR_INSTALLER_URL ( - set "INSTALLER_URL=%HERDR_INSTALLER_URL%" - set "CURL_PROTOCOL=--proto =http,https" -) -set "INSTALLER_PATH=%TEMP%\herdr-install-%RANDOM%-%RANDOM%.ps1" - -curl.exe --fail --silent --show-error --location --connect-timeout 30 --speed-limit 1024 --speed-time 30 %CURL_PROTOCOL% --output "%INSTALLER_PATH%" -- "%INSTALLER_URL%" -if errorlevel 1 ( - del /f /q "%INSTALLER_PATH%" >nul 2>&1 - exit /b 1 -) - -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%INSTALLER_PATH%" %* -set "INSTALLER_EXIT=%ERRORLEVEL%" -del /f /q "%INSTALLER_PATH%" >nul 2>&1 -exit /b %INSTALLER_EXIT% diff --git a/website/install.ps1 b/website/install.ps1 deleted file mode 100644 index 94a57314..00000000 --- a/website/install.ps1 +++ /dev/null @@ -1,871 +0,0 @@ -[CmdletBinding()] -param( - [string]$Channel = $env:HERDR_CHANNEL, - [string]$ManifestUrl = $env:HERDR_MANIFEST_URL, - [string]$InstallDir = $env:HERDR_INSTALL_DIR, - [string]$ExpectedBuildId = $env:HERDR_EXPECTED_BUILD_ID, - [int]$Retain = 3, - [string]$LocalPackagePath, - [string]$LocalPackageFormat, - [string]$LocalPackageIdentity, - [string]$LocalPackageSha256 -) - -Set-StrictMode -Version Latest -$ErrorActionPreference = "Stop" -$ProgressPreference = "SilentlyContinue" - -$channelWasExplicit = -not [string]::IsNullOrWhiteSpace($Channel) -if ($channelWasExplicit -and $Channel -notin @("stable", "preview")) { - Write-Error "Invalid Herdr channel '$Channel'. Use 'stable' or 'preview'." - exit 1 -} - -$localPackageValueCount = @( - $LocalPackagePath, - $LocalPackageFormat, - $LocalPackageIdentity, - $LocalPackageSha256 | - Where-Object { -not [string]::IsNullOrWhiteSpace($_) } -).Count -if ($localPackageValueCount -notin @(0, 4)) { - throw "Local package mode requires path, format, identity, and SHA-256." -} -$useLocalPackage = $localPackageValueCount -eq 4 -if ($useLocalPackage -and $LocalPackageFormat -notin @("zip", "exe")) { - throw "Local Herdr package has unsupported format '$LocalPackageFormat'." -} - -function Write-Step { - param([string]$Message) - Write-Host "==> $Message" -} - -function Write-WarningStep { - param([string]$Message) - Write-Warning $Message -} - -function Get-HerdrCommandSource { - $existing = Get-Command herdr -ErrorAction SilentlyContinue - if ($null -eq $existing) { - return $null - } - - return $existing.Source -} - -function Test-PathStartsWith { - param( - [string]$Path, - [string]$Prefix - ) - - if ([string]::IsNullOrWhiteSpace($Path) -or [string]::IsNullOrWhiteSpace($Prefix)) { - return $false - } - - try { - $normalizedPath = [System.IO.Path]::GetFullPath($Path) - $normalizedPrefix = [System.IO.Path]::GetFullPath($Prefix).TrimEnd("\") + "\" - return $normalizedPath.StartsWith($normalizedPrefix, [System.StringComparison]::OrdinalIgnoreCase) - } catch { - return $false - } -} - -function Path-Contains { - param( - [string]$PathValue, - [string]$Entry - ) - - if ([string]::IsNullOrWhiteSpace($PathValue)) { - return $false - } - - $needle = $Entry.TrimEnd("\") - foreach ($segment in $PathValue.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries)) { - if ($segment.TrimEnd("\") -ieq $needle) { - return $true - } - } - - return $false -} - -function Prepend-PathEntry { - param( - [string]$PathValue, - [string]$Entry - ) - - $needle = $Entry.TrimEnd("\") - $segments = @($Entry) - if (-not [string]::IsNullOrWhiteSpace($PathValue)) { - $segments += $PathValue.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries) | - Where-Object { $_.TrimEnd("\") -ine $needle } - } - - return ($segments -join ";") -} - -function Update-PathRegistryEntry { - param( - [Microsoft.Win32.RegistryKey]$EnvironmentKey, - [string]$Entry - ) - - $options = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames - $value = $EnvironmentKey.GetValue("Path", $null, $options) - $kind = if ($null -eq $value) { - [Microsoft.Win32.RegistryValueKind]::String - } else { - $EnvironmentKey.GetValueKind("Path") - } - $newValue = Prepend-PathEntry -PathValue $value -Entry $Entry - if ($newValue -ceq $value) { - return $false - } - - $EnvironmentKey.SetValue("Path", $newValue, $kind) - return $true -} - -function Publish-EnvironmentChange { - if (-not ("HerdrInstaller.EnvironmentNativeMethods" -as [type])) { - Add-Type -Namespace HerdrInstaller -Name EnvironmentNativeMethods -MemberDefinition @' -[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] -public static extern System.IntPtr SendMessageTimeout( - System.IntPtr hWnd, - uint message, - System.UIntPtr wParam, - string lParam, - uint flags, - uint timeout, - out System.UIntPtr result); -'@ - } - - $result = [UIntPtr]::Zero - [HerdrInstaller.EnvironmentNativeMethods]::SendMessageTimeout( - [IntPtr]0xffff, - 0x1a, - [UIntPtr]::Zero, - "Environment", - 0x0002, - 1000, - [ref]$result - ) | Out-Null -} - -function Get-ManifestAsset { - param( - [object]$Manifest, - [string]$Target - ) - - $property = $Manifest.assets.PSObject.Properties[$Target] - if ($null -eq $property) { - throw "Release manifest does not include a binary for $Target." - } - - $sha256 = $null - $shaMapProperty = $Manifest.PSObject.Properties["sha256"] - if ($null -ne $shaMapProperty -and $null -ne $shaMapProperty.Value) { - $targetShaProperty = $shaMapProperty.Value.PSObject.Properties[$Target] - if ($null -ne $targetShaProperty -and -not [string]::IsNullOrWhiteSpace([string]$targetShaProperty.Value)) { - $sha256 = [string]$targetShaProperty.Value - } - } - - $asset = $property.Value - if ($asset -is [string]) { - $url = [string]$asset - return [PSCustomObject]@{ - Url = $url - Sha256 = $sha256 - Format = if ($url.EndsWith(".zip", [System.StringComparison]::OrdinalIgnoreCase)) { "zip" } else { "exe" } - } - } - - $urlProperty = $asset.PSObject.Properties["url"] - if ($null -eq $urlProperty -or [string]::IsNullOrWhiteSpace([string]$urlProperty.Value)) { - throw "Release manifest asset $Target is missing a URL." - } - - $url = [string]$urlProperty.Value - $formatProperty = $asset.PSObject.Properties["format"] - $format = if ($null -eq $formatProperty -or [string]::IsNullOrWhiteSpace([string]$formatProperty.Value)) { - if ($url.EndsWith(".zip", [System.StringComparison]::OrdinalIgnoreCase)) { "zip" } else { "exe" } - } else { - [string]$formatProperty.Value - } - if ($format -notin @("zip", "exe")) { - throw "Release manifest asset $Target has unsupported format '$format'." - } - $shaProperty = $asset.PSObject.Properties["sha256"] - if ($null -ne $shaProperty -and -not [string]::IsNullOrWhiteSpace([string]$shaProperty.Value)) { - $sha256 = [string]$shaProperty.Value - } - - return [PSCustomObject]@{ - Url = $url - Sha256 = $sha256 - Format = $format - } -} - -function Invoke-CurlDownload { - param( - [string]$Uri, - [string]$Destination - ) - - $parsedUri = $null - if (-not [System.Uri]::TryCreate($Uri, [System.UriKind]::Absolute, [ref]$parsedUri) -or - $parsedUri.Scheme -notin @("http", "https")) { - throw "Herdr download URL must use HTTP or HTTPS: $Uri" - } - - $curl = Get-Command curl.exe -CommandType Application -ErrorAction SilentlyContinue | - Select-Object -First 1 - if ($null -eq $curl) { - throw "Herdr installation requires curl.exe, which is included with supported Windows versions." - } - - $arguments = @( - "--fail", - "--silent", - "--show-error", - "--location", - "--connect-timeout", "30", - "--speed-limit", "1024", - "--speed-time", "30" - ) - if ($parsedUri.Scheme -eq "https") { - $arguments += @("--proto", "=https", "--tlsv1.2") - } - $arguments += @("--output", $Destination, "--", $Uri) - - $curlOutput = & $curl.Source @arguments 2>&1 - $curlExitCode = $LASTEXITCODE - if ($curlExitCode -ne 0) { - $detail = ($curlOutput | ForEach-Object { $_.ToString() }) -join [Environment]::NewLine - $message = "Failed to download $Uri (curl exit code $curlExitCode)." - if (-not [string]::IsNullOrWhiteSpace($detail)) { - $message += " $detail" - } - throw $message - } -} - -function ConvertTo-ManifestObject { - param([object]$Manifest) - - if ($Manifest -isnot [string]) { - return $Manifest - } - - $json = $Manifest.TrimStart([char]0xFEFF) - $utf8BomDecodedAsLatin1 = [string]::Concat([char]0x00EF, [char]0x00BB, [char]0x00BF) - if ($json.StartsWith($utf8BomDecodedAsLatin1)) { - $json = $json.Substring(3) - } - - return $json | ConvertFrom-Json -} - -function Get-RemoteManifest { - param([string]$Uri) - - $manifestPath = Join-Path ([System.IO.Path]::GetTempPath()) ("herdr-manifest-" + [System.Guid]::NewGuid().ToString("N") + ".json") - try { - Invoke-CurlDownload -Uri $Uri -Destination $manifestPath - return ConvertTo-ManifestObject -Manifest ([System.IO.File]::ReadAllText($manifestPath)) - } finally { - Remove-Item -LiteralPath $manifestPath -Force -ErrorAction SilentlyContinue - } -} - -function Test-FileDigest { - param( - [string]$Path, - [string]$ExpectedDigest - ) - - if ([string]::IsNullOrWhiteSpace($ExpectedDigest)) { - throw "A SHA-256 checksum is required for $Path." - } - if ($ExpectedDigest -notmatch '^[0-9a-fA-F]{64}$') { - throw "Invalid SHA-256 checksum for $Path." - } - - $sha256 = [System.Security.Cryptography.SHA256]::Create() - try { - $bytes = [System.IO.File]::ReadAllBytes($Path) - $actual = [System.BitConverter]::ToString($sha256.ComputeHash($bytes)).Replace("-", "").ToLowerInvariant() - } finally { - $sha256.Dispose() - } - if ($actual -ne $ExpectedDigest.ToLowerInvariant()) { - throw "Downloaded Herdr checksum did not match. Expected $ExpectedDigest but got $actual." - } -} - -function Test-RegularFile { - param([string]$Path) - - if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { - return $false - } - $item = Get-Item -LiteralPath $Path -Force - return -not ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -} - -function Test-RegularDirectory { - param([string]$Path) - - if (-not (Test-Path -LiteralPath $Path -PathType Container)) { - return $false - } - $item = Get-Item -LiteralPath $Path -Force - return -not ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -} - -function Test-HerdrReleaseComplete { - param( - [string]$ReleaseDir, - [string]$Format - ) - - if (-not (Test-RegularDirectory -Path $ReleaseDir)) { - return $false - } - $herdrExe = Join-Path $ReleaseDir "herdr.exe" - if (-not (Test-RegularFile -Path $herdrExe)) { - return $false - } - if ($Format -eq "exe") { - return $true - } - - $conptyRoot = Join-Path $ReleaseDir "conpty" - if (-not (Test-RegularDirectory -Path $conptyRoot) -or - -not (Test-RegularDirectory -Path (Join-Path $conptyRoot "x64")) -or - -not (Test-RegularDirectory -Path (Join-Path $conptyRoot "arm64"))) { - return $false - } - $markerPath = Join-Path $conptyRoot "herdr-conpty.json" - $required = @( - "conpty/conpty.dll", - "conpty/x64/OpenConsole.exe", - "conpty/arm64/OpenConsole.exe", - "THIRD-PARTY-NOTICES/Microsoft.Windows.Console.ConPTY-LICENSE.txt", - "THIRD-PARTY-NOTICES/Microsoft.Windows.Console.ConPTY-NOTICE.md" - ) - foreach ($relative in $required) { - if (-not (Test-RegularFile -Path (Join-Path $ReleaseDir ($relative -replace '/', '\')))) { - return $false - } - } - if (-not (Test-RegularFile -Path $markerPath)) { - return $false - } - - try { - $marker = ConvertTo-ManifestObject -Manifest (Get-Content -LiteralPath $markerPath -Raw) - $schemaProperty = $marker.PSObject.Properties["schema_version"] - $packageProperty = $marker.PSObject.Properties["package"] - $versionProperty = $marker.PSObject.Properties["version"] - $architectureProperty = $marker.PSObject.Properties["architecture"] - $filesProperty = $marker.PSObject.Properties["files"] - if ($null -eq $schemaProperty -or [int]$schemaProperty.Value -ne 1 -or - $null -eq $packageProperty -or [string]$packageProperty.Value -ne "Microsoft.Windows.Console.ConPTY" -or - $null -eq $versionProperty -or [string]::IsNullOrWhiteSpace([string]$versionProperty.Value) -or - $null -eq $architectureProperty -or [string]$architectureProperty.Value -ne "x86_64" -or - $null -eq $filesProperty) { - return $false - } - - $expectedConptyFiles = @( - "conpty/conpty.dll", - "conpty/x64/OpenConsole.exe", - "conpty/arm64/OpenConsole.exe" - ) - $markerFileNames = @($filesProperty.Value.PSObject.Properties | ForEach-Object { $_.Name }) - if (@(Compare-Object $expectedConptyFiles $markerFileNames).Count -ne 0) { - return $false - } - - $bundleEntries = @(Get-ChildItem -LiteralPath $conptyRoot -Force -Recurse) - if (@($bundleEntries | Where-Object { - $_.Attributes -band [IO.FileAttributes]::ReparsePoint - }).Count -ne 0) { - return $false - } - $releaseRoot = [System.IO.Path]::GetFullPath($ReleaseDir).TrimEnd('\') - $actualBundleFiles = @($bundleEntries | Where-Object { -not $_.PSIsContainer } | ForEach-Object { - $_.FullName.Substring($releaseRoot.Length + 1).Replace('\', '/') - }) - $expectedBundleFiles = @($expectedConptyFiles) + "conpty/herdr-conpty.json" - if (@(Compare-Object $expectedBundleFiles $actualBundleFiles).Count -ne 0) { - return $false - } - foreach ($relative in $expectedConptyFiles) { - $digestProperty = $filesProperty.Value.PSObject.Properties[$relative] - if ($null -eq $digestProperty) { - return $false - } - Test-FileDigest -Path (Join-Path $ReleaseDir ($relative -replace '/', '\')) -ExpectedDigest ([string]$digestProperty.Value) - } - } catch { - return $false - } - return $true -} - -function Move-DirectoryWithRetry { - param( - [string]$Source, - [string]$Destination, - [int]$TimeoutMilliseconds = 5000 - ) - - $deadline = [DateTime]::UtcNow.AddMilliseconds($TimeoutMilliseconds) - while ($true) { - try { - [System.IO.Directory]::Move($Source, $Destination) - return - } catch { - $retryable = $false - $exception = $_.Exception - while ($null -ne $exception) { - if ($exception -is [System.IO.IOException] -or - $exception -is [System.UnauthorizedAccessException]) { - $retryable = $true - break - } - $exception = $exception.InnerException - } - if (-not $retryable -or - [DateTime]::UtcNow -ge $deadline -or - -not (Test-Path -LiteralPath $Source -PathType Container) -or - (Test-Path -LiteralPath $Destination)) { - throw - } - Start-Sleep -Milliseconds 100 - } - } -} - -function Remove-DirectoryWithRetry { - param( - [string]$Path, - [int]$TimeoutMilliseconds = 5000 - ) - - $fullPath = [System.IO.Path]::GetFullPath($Path) - $extendedPath = if ($fullPath.StartsWith("\\")) { - "\\?\UNC\" + $fullPath.TrimStart([char]'\') - } else { - "\\?\" + $fullPath - } - $deadline = [DateTime]::UtcNow.AddMilliseconds($TimeoutMilliseconds) - while (Test-Path -LiteralPath $Path) { - try { - [System.IO.Directory]::Delete($extendedPath, $true) - return - } catch { - if ([DateTime]::UtcNow -ge $deadline) { - Write-WarningStep "Herdr installed successfully but could not remove a temporary release backup at $Path." - return - } - Start-Sleep -Milliseconds 100 - } - } -} - -function Invoke-WithInstallLock { - param( - [string]$LockPath, - [scriptblock]$Script - ) - - New-Item -ItemType Directory -Force -Path (Split-Path -Parent $LockPath) | Out-Null - $lock = $null - while ($null -eq $lock) { - try { - $lock = [System.IO.File]::Open( - $LockPath, - [System.IO.FileMode]::OpenOrCreate, - [System.IO.FileAccess]::ReadWrite, - [System.IO.FileShare]::None - ) - } catch [System.IO.IOException] { - Start-Sleep -Milliseconds 250 - } - } - - try { - & $Script - } finally { - $lock.Dispose() - } -} - -function Test-IsJunction { - param([string]$Path) - - if (-not (Test-Path -LiteralPath $Path)) { - return $false - } - - $item = Get-Item -LiteralPath $Path -Force - return ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -and $item.LinkType -eq "Junction" -} - -function Set-ManagedJunction { - param( - [string]$LinkPath, - [string]$TargetPath, - [string]$ManagedTargetPrefix, - [bool]$AllowLegacyHerdrBinMigration = $false - ) - - if (Test-Path -LiteralPath $LinkPath) { - $item = Get-Item -LiteralPath $LinkPath -Force - if (Test-IsJunction -Path $LinkPath) { - $existingTarget = [string]$item.Target - if (-not [string]::IsNullOrWhiteSpace($ManagedTargetPrefix)) { - $ownedPrefix = $ManagedTargetPrefix.TrimEnd("\") - if (-not $existingTarget.StartsWith($ownedPrefix, [System.StringComparison]::OrdinalIgnoreCase)) { - throw "Refusing to retarget junction at $LinkPath because it is not managed by this installer." - } - } - if ($existingTarget.Equals($TargetPath, [System.StringComparison]::OrdinalIgnoreCase)) { - return - } - Remove-Item -LiteralPath $LinkPath -Recurse -Force - } elseif ($item.PSIsContainer) { - if ((Get-ChildItem -LiteralPath $LinkPath -Force | Select-Object -First 1) -ne $null) { - if (-not (Move-LegacyHerdrBinDirectory -Path $LinkPath -AllowMigration $AllowLegacyHerdrBinMigration)) { - throw "Refusing to replace non-empty directory at $LinkPath with a junction." - } - } else { - Remove-Item -LiteralPath $LinkPath -Recurse -Force - } - } else { - throw "Refusing to replace file at $LinkPath with a junction." - } - } - - New-Item -ItemType Directory -Force -Path (Split-Path -Parent $LinkPath) | Out-Null - New-Item -ItemType Junction -Path $LinkPath -Target $TargetPath | Out-Null -} - -function Move-LegacyHerdrBinDirectory { - param( - [string]$Path, - [bool]$AllowMigration - ) - - if (-not $AllowMigration) { - return $false - } - - $entries = @(Get-ChildItem -LiteralPath $Path -Force) - if (($entries | Where-Object { $_.PSIsContainer } | Select-Object -First 1) -ne $null) { - return $false - } - - if (($entries | Where-Object { $_.Name -ieq "herdr.exe" } | Select-Object -First 1) -eq $null) { - return $false - } - - $legacyPath = "$Path.legacy.$([System.Guid]::NewGuid().ToString("N"))" - Move-Item -LiteralPath $Path -Destination $legacyPath - Write-Step "Moved legacy Herdr bin directory to $legacyPath." - return $true -} - -function Remove-StaleInstallArtifacts { - param([string]$ReleasesDir) - - if (-not (Test-Path -LiteralPath $ReleasesDir -PathType Container)) { - return - } - - Get-ChildItem -LiteralPath $ReleasesDir -Force -Directory -Filter ".staging.*" -ErrorAction SilentlyContinue | - Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -} - -function Remove-OldReleases { - param( - [string]$ReleasesDir, - [string]$CurrentReleaseDir, - [int]$Keep - ) - - if ($Keep -lt 1 -or -not (Test-Path -LiteralPath $ReleasesDir -PathType Container)) { - return - } - - $currentFullPath = [System.IO.Path]::GetFullPath($CurrentReleaseDir) - $releaseDirs = Get-ChildItem -LiteralPath $ReleasesDir -Force -Directory -ErrorAction SilentlyContinue | - Where-Object { -not $_.Name.StartsWith(".staging.") -and -not $_.Name.StartsWith(".backup.") } | - Sort-Object LastWriteTimeUtc -Descending - $kept = 0 - foreach ($dir in $releaseDirs) { - $dirFullPath = [System.IO.Path]::GetFullPath($dir.FullName) - if ($dirFullPath.Equals($currentFullPath, [System.StringComparison]::OrdinalIgnoreCase)) { - $kept += 1 - continue - } - if ($kept -lt $Keep) { - $kept += 1 - continue - } - Remove-Item -LiteralPath $dir.FullName -Recurse -Force -ErrorAction SilentlyContinue - } -} - -function Resolve-HerdrVersion { - param( - [object]$Manifest, - [string]$SelectedChannel - ) - - if ($SelectedChannel -eq "preview") { - if ([string]::IsNullOrWhiteSpace([string]$Manifest.base_version) -or [string]::IsNullOrWhiteSpace([string]$Manifest.build_id)) { - throw "Preview manifest is missing base_version or build_id." - } - return "$($Manifest.base_version)-preview.$($Manifest.build_id)" - } - - if ([string]::IsNullOrWhiteSpace([string]$Manifest.version)) { - throw "Stable manifest is missing version." - } - return [string]$Manifest.version -} - -if ($env:OS -ne "Windows_NT") { - Write-Error "install.ps1 supports Windows only. Use install.sh on Linux or macOS." - exit 1 -} - -if (-not [Environment]::Is64BitOperatingSystem) { - Write-Error "Herdr requires 64-bit Windows." - exit 1 -} - -$architecture = [System.Runtime.InteropServices.RuntimeInformation,mscorlib]::OSArchitecture.ToString() -switch ($architecture) { - "X64" { - $target = "windows-x86_64" - $targetTriple = "x86_64-pc-windows-msvc" - } - "Arm64" { - $target = "windows-x86_64" - $targetTriple = "x86_64-pc-windows-msvc" - Write-Step "Windows ARM64 detected; installing the x86_64 build under Windows emulation." - } - default { - Write-Error "Unsupported Windows architecture: $architecture" - exit 1 - } -} - -$herdrHome = if ([string]::IsNullOrWhiteSpace($env:HERDR_HOME)) { - Join-Path $env:USERPROFILE ".herdr" -} else { - $env:HERDR_HOME -} -$herdrHome = [System.IO.Path]::GetFullPath($herdrHome) -$standaloneRoot = Join-Path $herdrHome "packages\standalone" -$releasesDir = Join-Path $standaloneRoot "releases" -$currentDir = Join-Path $standaloneRoot "current" -$lockPath = Join-Path $standaloneRoot "install.lock" - -$defaultVisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\Herdr\bin" -$visibleBinDir = if ([string]::IsNullOrWhiteSpace($InstallDir)) { - $defaultVisibleBinDir -} else { - $InstallDir -} -$allowLegacyVisibleBinMigration = $false -try { - $allowLegacyVisibleBinMigration = [System.IO.Path]::GetFullPath($visibleBinDir).TrimEnd("\").Equals( - [System.IO.Path]::GetFullPath($defaultVisibleBinDir).TrimEnd("\"), - [System.StringComparison]::OrdinalIgnoreCase - ) -} catch { - $allowLegacyVisibleBinMigration = $false -} - -$existingHerdr = Get-HerdrCommandSource -if (-not [string]::IsNullOrWhiteSpace($existingHerdr) -and -not (Test-PathStartsWith -Path $existingHerdr -Prefix $visibleBinDir)) { - Write-Step "Detected existing Herdr command at $existingHerdr" - Write-WarningStep "PATH order decides which Herdr runs. This installer will put $visibleBinDir first for future and current PowerShell sessions." -} - -if ($useLocalPackage) { - $versionIdentity = $LocalPackageIdentity - $asset = [PSCustomObject]@{ - Sha256 = $LocalPackageSha256 - Format = $LocalPackageFormat - } -} else { - if (-not $channelWasExplicit) { - if (-not [string]::IsNullOrWhiteSpace($existingHerdr)) { - $detectedChannel = [string](& $existingHerdr channel show 2>$null | Select-Object -Last 1) - $detectedChannel = $detectedChannel.Trim() - if ($LASTEXITCODE -ne 0 -or $detectedChannel -notin @("stable", "preview")) { - throw "Could not determine the existing Herdr update channel. Rerun with -Channel stable or -Channel preview." - } - $Channel = $detectedChannel - Write-Step "Preserving existing Herdr $Channel channel" - } elseif (-not [string]::IsNullOrWhiteSpace($ManifestUrl) -and $ManifestUrl -match "/preview\.json$") { - $Channel = "preview" - } else { - $Channel = "stable" - } - } - - if ([string]::IsNullOrWhiteSpace($ManifestUrl)) { - $ManifestUrl = if ($Channel -eq "preview") { - "https://herdr.dev/preview.json" - } else { - "https://herdr.dev/latest.json" - } - } - - Write-Step "Fetching Herdr $Channel manifest" - $manifest = Get-RemoteManifest -Uri $ManifestUrl - $manifestChannelProperty = $manifest.PSObject.Properties["channel"] - if (-not $channelWasExplicit -and $null -ne $manifestChannelProperty -and [string]$manifestChannelProperty.Value -eq "preview") { - $Channel = "preview" - } - $assetsProperty = $manifest.PSObject.Properties["assets"] - $assetProperty = if ($null -eq $assetsProperty) { - $null - } else { - $assetsProperty.Value.PSObject.Properties[$target] - } - if ($null -eq $assetProperty -and - -not $channelWasExplicit -and - $Channel -eq "stable" -and - $ManifestUrl -match "/latest\.json$") { - Write-WarningStep "The stable manifest does not include Windows yet; using preview during the stable-channel rollout." - $Channel = "preview" - $ManifestUrl = $ManifestUrl.Substring(0, $ManifestUrl.Length - "latest.json".Length) + "preview.json" - Write-Step "Fetching Herdr preview manifest" - $manifest = Get-RemoteManifest -Uri $ManifestUrl - } - $asset = Get-ManifestAsset -Manifest $manifest -Target $target - if (-not [string]::IsNullOrWhiteSpace($ExpectedBuildId) -and [string]$manifest.build_id -ne $ExpectedBuildId) { - throw "Preview manifest changed while updating. Expected build $ExpectedBuildId but found $($manifest.build_id). Run herdr update again." - } - $versionIdentity = Resolve-HerdrVersion -Manifest $manifest -SelectedChannel $Channel -} -$safeVersionIdentity = $versionIdentity -replace '[^0-9A-Za-z._-]', '-' -$releaseName = "$safeVersionIdentity-$targetTriple" -$releaseDir = Join-Path $releasesDir $releaseName - -Write-Step "Installing Herdr $versionIdentity for $targetTriple" -$tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ("herdr-install-" + [System.Guid]::NewGuid().ToString("N")) -New-Item -ItemType Directory -Force -Path $tempDir | Out-Null - -try { - Invoke-WithInstallLock -LockPath $lockPath -Script { - Remove-StaleInstallArtifacts -ReleasesDir $releasesDir - - if (-not (Test-HerdrReleaseComplete -ReleaseDir $releaseDir -Format $asset.Format)) { - $downloadPath = if ($useLocalPackage) { - $LocalPackagePath - } else { - Join-Path $tempDir "herdr-download.$($asset.Format)" - } - $stagingDir = Join-Path $releasesDir ".staging.$releaseName.$PID" - if (-not $useLocalPackage) { - Write-Step "Downloading Herdr" - Invoke-CurlDownload -Uri $asset.Url -Destination $downloadPath - } - Test-FileDigest -Path $downloadPath -ExpectedDigest $asset.Sha256 - - if ($asset.Format -eq "zip") { - Expand-Archive -LiteralPath $downloadPath -DestinationPath $stagingDir - } else { - New-Item -ItemType Directory -Force -Path $stagingDir | Out-Null - Copy-Item -LiteralPath $downloadPath -Destination (Join-Path $stagingDir "herdr.exe") - } - if (-not (Test-HerdrReleaseComplete -ReleaseDir $stagingDir -Format $asset.Format)) { - throw "Downloaded Herdr package is incomplete or failed ConPTY verification." - } - $stagedHerdr = Join-Path $stagingDir "herdr.exe" - & $stagedHerdr --version *> $null - if ($LASTEXITCODE -ne 0) { - throw "Downloaded Herdr command failed verification: $stagedHerdr --version" - } - $backupDir = $null - if (Test-Path -LiteralPath $releaseDir) { - $backupDir = Join-Path $releasesDir ".backup.$releaseName.$([System.Guid]::NewGuid().ToString('N'))" - [System.IO.Directory]::Move($releaseDir, $backupDir) - } - try { - Move-DirectoryWithRetry -Source $stagingDir -Destination $releaseDir - } catch { - if ($null -ne $backupDir -and -not (Test-Path -LiteralPath $releaseDir)) { - [System.IO.Directory]::Move($backupDir, $releaseDir) - } - Write-WarningStep "Windows could not activate the downloaded release. Another process may have a package file open, such as antivirus or indexing. No incomplete release was activated. Run herdr update again." - throw - } - } - - $releaseHerdr = Join-Path $releaseDir "herdr.exe" - & $releaseHerdr --version *> $null - if ($LASTEXITCODE -ne 0) { - throw "Installed Herdr command failed verification: $releaseHerdr --version" - } - Get-ChildItem -LiteralPath $releasesDir -Force -Directory -Filter ".backup.$releaseName.*" -ErrorAction SilentlyContinue | - ForEach-Object { Remove-DirectoryWithRetry -Path $_.FullName } - - Set-ManagedJunction -LinkPath $currentDir -TargetPath $releaseDir -ManagedTargetPrefix $releasesDir - Set-ManagedJunction -LinkPath $visibleBinDir -TargetPath $releaseDir -ManagedTargetPrefix $standaloneRoot -AllowLegacyHerdrBinMigration $allowLegacyVisibleBinMigration - - Remove-OldReleases -ReleasesDir $releasesDir -CurrentReleaseDir $releaseDir -Keep $Retain - } -} finally { - Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue -} - -$userEnvironmentKey = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey("Environment") -if ($null -eq $userEnvironmentKey) { - throw "Unable to open the current user's environment registry key." -} -try { - $userPathChanged = Update-PathRegistryEntry -EnvironmentKey $userEnvironmentKey -Entry $visibleBinDir -} finally { - $userEnvironmentKey.Dispose() -} -if ($userPathChanged) { - Publish-EnvironmentChange - Write-Step "PATH updated for future PowerShell sessions." -} else { - Write-Step "$visibleBinDir is already first on PATH." -} - -$newProcessPath = Prepend-PathEntry -PathValue $env:Path -Entry $visibleBinDir -if ($newProcessPath -cne $env:Path) { - $env:Path = $newProcessPath -} - -$resolvedHerdr = Get-HerdrCommandSource -if (-not (Test-PathStartsWith -Path $resolvedHerdr -Prefix $visibleBinDir)) { - Write-WarningStep "PowerShell still resolves herdr to $resolvedHerdr. Open a new PowerShell window or inspect PATH order manually." -} - -Write-Step "Current PowerShell session: herdr" -Write-Step "Future PowerShell windows: open a new PowerShell window and run: herdr" -Write-Host "Herdr $versionIdentity installed successfully." diff --git a/website/install.sh b/website/install.sh deleted file mode 100755 index 4e3ce40d..00000000 --- a/website/install.sh +++ /dev/null @@ -1,146 +0,0 @@ -#!/bin/sh -set -eu - -BIN="herdr" -MANIFEST_URL="https://herdr.dev/latest.json" -INSTALL_DIR="${HERDR_INSTALL_DIR:-$HOME/.local/bin}" - -main() { - echo "" - echo " ,ww" - echo " wWWWWWWW_) herdr installer" - echo " \`WWWWWW' herdr.dev" - echo " II II" - echo "" - - # detect platform - OS="$(uname -s)" - case "$OS" in - Linux) os="linux" ;; - Darwin) os="macos" ;; - *) err "unsupported OS: $OS" ;; - esac - - ARCH="$(uname -m)" - case "$ARCH" in - x86_64|amd64) arch="x86_64" ;; - aarch64|arm64) arch="aarch64" ;; - *) err "unsupported architecture: $ARCH" ;; - esac - - log "detected ${os}/${arch}" - - # check dependencies - need curl - need awk - - # use the same manifest as `herdr update` so installs and updates agree - # on the public latest release. - TARGET="${os}-${arch}" - log "fetching latest release manifest..." - MANIFEST="$(curl -fsSL --retry 3 --connect-timeout 10 --max-time 20 "$MANIFEST_URL")" \ - || err "can't reach ${MANIFEST_URL}. Please try again later; herdr.dev might be down. Who let the sheeps out? baaa." - URL="$(printf '%s\n' "$MANIFEST" | awk -v target="\"${TARGET}\"" ' - /^[[:space:]]*"assets"[[:space:]]*:/ { in_assets = 1; next } - in_assets && /^[[:space:]]*}/ { exit } - in_assets && index($0, target) { - sub(/^.*:[[:space:]]*"/, "") - sub(/".*$/, "") - print - exit - } - ')" - SHA256="$(printf '%s\n' "$MANIFEST" | awk -v target="\"${TARGET}\"" ' - /^[[:space:]]*"sha256"[[:space:]]*:/ { in_sha256 = 1; next } - in_sha256 && /^[[:space:]]*}/ { exit } - in_sha256 && index($0, target) { - sub(/^.*:[[:space:]]*"/, "") - sub(/".*$/, "") - print - exit - } - ')" - VERSION="$(printf '%s\n' "$MANIFEST" | awk -F '"' '/^[[:space:]]*"version"[[:space:]]*:/ { print $4; exit }')" - - if [ -z "$URL" ]; then - err "release manifest does not include a binary for ${TARGET}" - fi - if [ "${#SHA256}" -ne 64 ]; then - err "release manifest does not include a valid SHA-256 checksum for ${TARGET}" - fi - if ! printf '%s\n' "$SHA256" | awk '/[^0-9A-Fa-f]/ { exit 1 }'; then - err "release manifest does not include a valid SHA-256 checksum for ${TARGET}" - fi - SHA256="$(printf '%s\n' "$SHA256" | awk '{ print tolower($0) }')" - - if command -v sha256sum >/dev/null 2>&1; then - SHA256_TOOL="sha256sum" - elif command -v shasum >/dev/null 2>&1; then - SHA256_TOOL="shasum" - elif command -v openssl >/dev/null 2>&1; then - SHA256_TOOL="openssl" - else - err "SHA-256 verification requires sha256sum, shasum, or openssl" - fi - - if [ -n "$VERSION" ]; then - log "downloading v${VERSION}..." - else - log "downloading latest release..." - fi - TMP="$(mktemp -d)" - trap 'rm -rf "$TMP"' EXIT - - if ! curl -fsSL --retry 3 --connect-timeout 10 --max-time 120 "$URL" -o "${TMP}/${BIN}"; then - err "download failed from ${URL}" - fi - - case "$SHA256_TOOL" in - sha256sum) ACTUAL_SHA256="$(sha256sum < "${TMP}/${BIN}" | awk '{ print $1 }')" ;; - shasum) ACTUAL_SHA256="$(shasum -a 256 < "${TMP}/${BIN}" | awk '{ print $1 }')" ;; - openssl) ACTUAL_SHA256="$(openssl dgst -sha256 < "${TMP}/${BIN}" | awk '{ print $NF }')" ;; - esac - if [ "$ACTUAL_SHA256" != "$SHA256" ]; then - err "downloaded Herdr checksum did not match" - fi - - # install - mkdir -p "$INSTALL_DIR" - mv "${TMP}/${BIN}" "${INSTALL_DIR}/${BIN}" - chmod +x "${INSTALL_DIR}/${BIN}" - - log "installed ${BIN} to ${INSTALL_DIR}/${BIN}" - - # check PATH - case ":${PATH}:" in - *":${INSTALL_DIR}:"*) ;; - *) - echo "" - warn "${INSTALL_DIR} is not in your PATH" - echo " add it to your shell config:" - echo "" - echo " export PATH=\"${INSTALL_DIR}:\$PATH\"" - echo "" - ;; - esac - - # verify - if command -v "$BIN" >/dev/null 2>&1; then - echo "" - log "ready. run 'herdr' to get started." - fi - - echo "" -} - -log() { printf ' \033[32m>\033[0m %s\n' "$1"; } -warn() { printf ' \033[33m!\033[0m %s\n' "$1"; } -err() { printf ' \033[31m✗\033[0m %s\n' "$1" >&2; exit 1; } - -need() { - if ! command -v "$1" >/dev/null 2>&1; then - err "requires '$1' — install it first, or download a binary manually from https://herdr.dev/docs/install/" - fi -} - -main "$@" diff --git a/website/latest.json b/website/latest.json deleted file mode 100644 index a0ffe777..00000000 --- a/website/latest.json +++ /dev/null @@ -1,556 +0,0 @@ -{ - "version": "0.8.2", - "protocol": 20, - "notes": "### Added\n- CLI help now points coding agents to Herdr's plain-text guide, documentation index, and built-in control skill.\n- Added Qwen Code detection for idle, working, and user-confirmation states, plus optional native session restore. (#2730, #2743)\n- Herdr now keeps the outer terminal window title in sync with the session through `ui.window_title`, so window managers and terminal tab bars show the active workspace and the host the panes actually run on. (#2627, thanks @dhh)\n- The desktop tab bar now has configurable right-aligned status entries for zoom state, hostname, date/time, literal text, and asynchronously refreshed command output.\n- Optional `keys.move_tab_previous` and `keys.move_tab_next` bindings now reorder the active tab in place, wrapping at either end. (#2561, thanks @dhh)\n- Optional `keys.resize_pane_left`, `keys.resize_pane_down`, `keys.resize_pane_up`, and `keys.resize_pane_right` bindings now resize the focused pane in one keystroke without entering resize mode. (#2558, thanks @dhh)\n- Windows clients can now use `herdr --remote` to attach to Herdr servers on Linux and macOS. (#2329)\n- Cursor Agent CLI, MastraCode, Hermes Agent, and Grok CLI integrations now install and run natively on Windows.\n- Panes can now route normal right-click gestures to mouse-reporting applications through the pane menu, `herdr pane input`, `pane.input.set`, or the `pane split --right-click pane` launch option.\n- `ui.pane_outer_borders` can now keep or hide the outside edges of split-pane borders independently from internal dividers. (#2535, thanks @dhh)\n- `theme.custom.sidebar_bg` can now give the desktop sidebar its own background without changing built-in theme defaults.\n- Settings and `ui.status_indicators = \"symbols\"` can now use distinct static shapes for blocked, working, done, idle, and unknown agent states. (#2260)\n- Navigate-mode selection rows now use a dedicated per-theme cursor color, customizable via `theme.custom.selection_bg`, so the cursor stays distinguishable from the active Space and Agent highlight.\n- Copy mode now supports `B`, `E`, and `W` motions over whitespace-delimited big words. (#2270, thanks @jplew)\n- The plugin marketplace now discovers valid manifests at repository roots and subdirectories, groups multiple plugins under each repository, and publishes their versions and exact default-branch commits.\n\n### Changed\n- Windows support is now generally available through stable releases and uses the stable update channel by default. Existing preview installs stay on preview until explicitly switched.\n- Headless servers now use a configurable 120\u00d740 virtual terminal instead of 80\u00d724 when no client is attached, giving newly created panes a practical default size. (#2828)\n- Desktop tab labels are now centered in their tabs, so the active-tab highlight has symmetric padding. (#2570, thanks @dhh)\n- Experimental pane graphics now support bounded named layers, acknowledged full-RGBA primary-layer direct file frames on audited local terminals, owned BGRA fallback, exact pixel mouse input, and placement-only resize replay.\n\n### Fixed\n- Unix CLI commands now exit quietly when a downstream pipe closes instead of panicking with exit 101. (#2994)\n- The terminal theme now keeps the active Space row fill visible when the Navigate cursor lands on it, in both expanded and collapsed sidebars. (#2987)\n- Busy multi-pane sessions now avoid redundant hidden-pane wakeups and full terminal-state formatting in pane-scaled paths, preventing CPU regressions from high-rate background output, scrollbars, and enhanced keyboard modes. (#2550, #2901, #2962)\n- Chinese IME commits now reach panes on macOS when the focused application requests printable key-release events. (#2924)\n- Windows now recognizes `Ctrl+1` through `Ctrl+9` keybindings instead of decoding those key records as control characters. (#2910)\n- PowerShell panes now keep their process-reported working directory synchronized with the shell's logical location. (#2879, thanks @Pimpmuckl)\n- Foreground typing no longer waits behind render cadence consumed by output from panes in hidden tabs. (#2890)\n- The Windows ARM64 installer now waits for x64 emulation to release the verified executable before activating the downloaded release. (#2916)\n- On Unix, Ctrl-click URL openers are now reaped after they exit, preventing defunct child processes from accumulating on long-running servers. (#2903)\n- Windows updates now reuse only verified local packages, avoiding security-tool download blocks while preserving checksum validation. (#2751, #2816, thanks @Pimpmuckl)\n- Herdr no longer sends the full OSC 4 palette query burst under WSL, preventing reply fragments from leaking into the shell through ConPTY. (#2440)\n- Qwen Code panes now use locale-independent terminal-title states and localized confirmation fallbacks, preventing active or blocked turns from appearing idle. (#2756)\n- Claude Code panes now recognize and strip every half-circle title spinner frame, preventing active turns from appearing idle and keeping titles clean. (#2707, #2709, #2760, #2762)\n- Copilot prompts now focus the target pane before sending input, so background panes do not silently drop prompts. (#1698, #2734, thanks @xkrogen)\n- Agent hooks now invoke the running Herdr binary instead of whichever binary appears first on `PATH`. (#2722, thanks @Pimpmuckl)\n- Closing a terminal running `herdr --remote` no longer produces a local client core dump while the remote session stays alive. (#2424)\n- Active Space and Agent rows now use dedicated theme colors that remain visible when the host terminal background matches the selected Herdr theme. (#2792)\n- `agent prompt` now rejects agents already waiting at approval or question dialogs with `agent_blocked`, without sending text or Enter. (#2788)\n- `agent start` now waits for new pane shells and first-run agent prompts to become ready instead of racing them or reporting premature readiness. (#2410, #2537, #2773, #2774, thanks @Pimpmuckl)\n- `prefix+e` now preserves logical lines when opening soft-wrapped scrollback in an editor. (#2733)\n- Alternate-screen pane reads avoid unnecessary ANSI formatting work, reducing read latency for TUI agents. (#2387, #2426)\n- Tab bar clicks are now properly registered when using Ghostty in native fullscreen. (#796, #2736, thanks @HackAttack)\n- Prefix keybindings now disambiguate layout-aware shifted punctuation, so a shifted `\\` no longer triggers `prefix+|` on keyboard layouts where the same key produces both characters. (#2674)\n- Remote clients now continue redrawing at very large terminal sizes instead of freezing when a full ANSI frame exceeds the transport limit. (#2670)\n- Windows Git status refreshes now reuse repository configuration instead of repeatedly triggering security scans for WSL repositories. (#2643, #2688, thanks @Pimpmuckl)\n- Windows idle agent detection now shares process snapshots across panes, reducing CPU use in sessions with many Git Bash panes. (#2459, #2494, #2642, #2651, thanks @Pimpmuckl)\n- Embedded bare repositories now derive the correct repository name and worktree location. (#2657, #2660)\n- Root-repository workspaces now retain their saved labels across update restarts. (#2594, #2727)\n- Elevated Windows panes no longer expose PowerShell's administrator decoration as the terminal title. (#2632, thanks @Pimpmuckl)\n- Modal name inputs now anchor the host IME cursor to the text field instead of the pane behind the dialog. (#1755, #2569, thanks @kataokatsuki)\n- Session Navigator movement ignores modified `j`, `k`, and arrow keys instead of consuming unrelated pane input. (#1981, #2377, thanks @atomsbaza)\n- OpenCode panes now track the root conversation selected in their own TUI for native restore without adopting activity from attached clients. (#2450)\n- Server stop requests now bypass pane and API traffic, preventing busy sessions from blocking shutdown or admitting a client while shutdown is pending. (#2612)\n- Fish `Ctrl+Alt` keybindings now work in panes after legacy Alt-prefixed control bytes are decoded with both modifiers. (#2514)\n- Windows recent-history reads no longer perform redundant snapshots, restoring `recent` output while reducing read cost. (#962, #2474, thanks @Pimpmuckl)\n- The Windows installer now activates releases with an atomic directory swap, preventing interrupted updates from leaving an empty release directory. (#2356, #2530, thanks @Pimpmuckl)\n- `herdr config check` now reports unknown built-in theme names instead of silently accepting them. (#2452)\n- macOS `herdr --remote` clients now keep the accepted bridge socket blocking, preventing an immediate disconnect after the protocol handshake. (#2478, thanks @mathijshenquet)\n- Prefix keybindings now preserve Shift in WezTerm Kitty keyboard mode, so commands such as config reload no longer trigger their unshifted action. (#2435)\n- Pane applications now receive modifyOtherKeys releases and shifted alternate reports without dropped releases or leaked Ctrl+Tab sequences. (#2296, #2302, #2303)\n- Detaching now restores host keyboard reporting, preventing enhanced keyboard sequences from leaking into the shell after Herdr exits. (#2393, #2395)\n- Default mouse reports are decoded instead of leaking escape bytes into the focused pane. (#2309, #2312)\n- BEL characters emitted by pane programs now reach the outer terminal so its audible and visual bell settings can react. (#2453)\n- Stable direct installs, self-updates, and remote helper downloads now require and verify the SHA-256 digest published for each GitHub release asset.\n- `pane read` and `pane wait-output` now accept `--flag=value` and options before or after the pane ID. (#2183, thanks @KyleCo76)\n- `pane current`, `pane get`, and `pane layout --current` now resolve the calling pane instead of another client's focused pane. (#2297, #2298)\n- Configs containing the retired Herdr-written `ui.agent_panel_scope` setting no longer report it as an unknown key after upgrades. (#2292)\n- Claude Code confirmation prompts using `Enter to confirm \u00b7 Esc to cancel` now report `blocked` instead of `idle`. (#2268)\n- Kiro CLI prompts now have positive idle detection instead of remaining in an unknown state. (#2301, thanks @smileynet)\n- Cursor's Run Everything footer no longer produces a false blocked state. (#1763, #2220, thanks @Nagi-ovo)\n- Versioned Python agent wrappers such as `python3.13` are now detected. (#2188, thanks @plarson)\n- Pi state reporting now ignores RPC, JSON, and print-mode helper processes that are not interactive TUI sessions. (#2159, thanks @rhjoh)\n- Collapsed workspace and Agent rows keep their status and active indicators visible, including with ten or more workspaces. (#2216, #2239, #2382, thanks @ianks)\n- Sidebar agent lists keep scrolling when differently sized clients are attached to the same session. (#2255, thanks @aiworkflowpro)\n- The Session Navigator now searches renamed single-tab labels. (#2320)\n- New splits return focus to the pane they were opened from. (#2266, thanks @jondkinney)\n- Halfwidth Katakana voiced and semi-voiced marks now render in the correct cell. (#2257, thanks @kazunari-kamata)\n- Ctrl-clicking a URL no longer forwards its release after the browser takes host focus, preventing duplicate tabs. (#2290, #2291, thanks @kataokatsuki)\n- OSC 4 palette overrides now render with the requested color instead of forwarding the palette index. (#2162, thanks @hamidi-dev)\n- Host terminal appearance is re-queried when focus returns, keeping automatic light and dark themes current. (#2416, #2417)\n- The bundled and installable Herdr agent skill now matches this stable release's CLI and lifecycle behavior. (#2847)\n- `pane send-keys` and `agent send-keys` now preserve Shift when sending `shift+tab`, allowing agent permission modes to be cycled programmatically. (#1561, thanks @keinstn and @tomohisa)", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-macos-aarch64", - "windows-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-windows-x86_64.zip" - }, - "sha256": { - "linux-x86_64": "976150a14d490c94b243ea2e1a7eb2dfb67f12e36b182db90936f6728e6aecf4", - "linux-aarch64": "f55610658e1c2e0d2aaef730b4b2ab885f7f8ba00285ab372bfb14f2e3d5b40d", - "macos-x86_64": "ab50262c8190cd7aa9056d249d255c08c328c3e8716de9cfa29db4f131b8e2c1", - "macos-aarch64": "a5d4f4d504d8b309c91f811050559300faba31258425f53c50852fc96f6ae574", - "windows-x86_64": "0ab3d0fe1434d55757997542b978c771d642987bb15a7130f4160f0db38821d5" - }, - "releases": { - "0.8.2": { - "notes": "### Added\n- CLI help now points coding agents to Herdr's plain-text guide, documentation index, and built-in control skill.\n- Added Qwen Code detection for idle, working, and user-confirmation states, plus optional native session restore. (#2730, #2743)\n- Herdr now keeps the outer terminal window title in sync with the session through `ui.window_title`, so window managers and terminal tab bars show the active workspace and the host the panes actually run on. (#2627, thanks @dhh)\n- The desktop tab bar now has configurable right-aligned status entries for zoom state, hostname, date/time, literal text, and asynchronously refreshed command output.\n- Optional `keys.move_tab_previous` and `keys.move_tab_next` bindings now reorder the active tab in place, wrapping at either end. (#2561, thanks @dhh)\n- Optional `keys.resize_pane_left`, `keys.resize_pane_down`, `keys.resize_pane_up`, and `keys.resize_pane_right` bindings now resize the focused pane in one keystroke without entering resize mode. (#2558, thanks @dhh)\n- Windows clients can now use `herdr --remote` to attach to Herdr servers on Linux and macOS. (#2329)\n- Cursor Agent CLI, MastraCode, Hermes Agent, and Grok CLI integrations now install and run natively on Windows.\n- Panes can now route normal right-click gestures to mouse-reporting applications through the pane menu, `herdr pane input`, `pane.input.set`, or the `pane split --right-click pane` launch option.\n- `ui.pane_outer_borders` can now keep or hide the outside edges of split-pane borders independently from internal dividers. (#2535, thanks @dhh)\n- `theme.custom.sidebar_bg` can now give the desktop sidebar its own background without changing built-in theme defaults.\n- Settings and `ui.status_indicators = \"symbols\"` can now use distinct static shapes for blocked, working, done, idle, and unknown agent states. (#2260)\n- Navigate-mode selection rows now use a dedicated per-theme cursor color, customizable via `theme.custom.selection_bg`, so the cursor stays distinguishable from the active Space and Agent highlight.\n- Copy mode now supports `B`, `E`, and `W` motions over whitespace-delimited big words. (#2270, thanks @jplew)\n- The plugin marketplace now discovers valid manifests at repository roots and subdirectories, groups multiple plugins under each repository, and publishes their versions and exact default-branch commits.\n\n### Changed\n- Windows support is now generally available through stable releases and uses the stable update channel by default. Existing preview installs stay on preview until explicitly switched.\n- Headless servers now use a configurable 120\u00d740 virtual terminal instead of 80\u00d724 when no client is attached, giving newly created panes a practical default size. (#2828)\n- Desktop tab labels are now centered in their tabs, so the active-tab highlight has symmetric padding. (#2570, thanks @dhh)\n- Experimental pane graphics now support bounded named layers, acknowledged full-RGBA primary-layer direct file frames on audited local terminals, owned BGRA fallback, exact pixel mouse input, and placement-only resize replay.\n\n### Fixed\n- Unix CLI commands now exit quietly when a downstream pipe closes instead of panicking with exit 101. (#2994)\n- The terminal theme now keeps the active Space row fill visible when the Navigate cursor lands on it, in both expanded and collapsed sidebars. (#2987)\n- Busy multi-pane sessions now avoid redundant hidden-pane wakeups and full terminal-state formatting in pane-scaled paths, preventing CPU regressions from high-rate background output, scrollbars, and enhanced keyboard modes. (#2550, #2901, #2962)\n- Chinese IME commits now reach panes on macOS when the focused application requests printable key-release events. (#2924)\n- Windows now recognizes `Ctrl+1` through `Ctrl+9` keybindings instead of decoding those key records as control characters. (#2910)\n- PowerShell panes now keep their process-reported working directory synchronized with the shell's logical location. (#2879, thanks @Pimpmuckl)\n- Foreground typing no longer waits behind render cadence consumed by output from panes in hidden tabs. (#2890)\n- The Windows ARM64 installer now waits for x64 emulation to release the verified executable before activating the downloaded release. (#2916)\n- On Unix, Ctrl-click URL openers are now reaped after they exit, preventing defunct child processes from accumulating on long-running servers. (#2903)\n- Windows updates now reuse only verified local packages, avoiding security-tool download blocks while preserving checksum validation. (#2751, #2816, thanks @Pimpmuckl)\n- Herdr no longer sends the full OSC 4 palette query burst under WSL, preventing reply fragments from leaking into the shell through ConPTY. (#2440)\n- Qwen Code panes now use locale-independent terminal-title states and localized confirmation fallbacks, preventing active or blocked turns from appearing idle. (#2756)\n- Claude Code panes now recognize and strip every half-circle title spinner frame, preventing active turns from appearing idle and keeping titles clean. (#2707, #2709, #2760, #2762)\n- Copilot prompts now focus the target pane before sending input, so background panes do not silently drop prompts. (#1698, #2734, thanks @xkrogen)\n- Agent hooks now invoke the running Herdr binary instead of whichever binary appears first on `PATH`. (#2722, thanks @Pimpmuckl)\n- Closing a terminal running `herdr --remote` no longer produces a local client core dump while the remote session stays alive. (#2424)\n- Active Space and Agent rows now use dedicated theme colors that remain visible when the host terminal background matches the selected Herdr theme. (#2792)\n- `agent prompt` now rejects agents already waiting at approval or question dialogs with `agent_blocked`, without sending text or Enter. (#2788)\n- `agent start` now waits for new pane shells and first-run agent prompts to become ready instead of racing them or reporting premature readiness. (#2410, #2537, #2773, #2774, thanks @Pimpmuckl)\n- `prefix+e` now preserves logical lines when opening soft-wrapped scrollback in an editor. (#2733)\n- Alternate-screen pane reads avoid unnecessary ANSI formatting work, reducing read latency for TUI agents. (#2387, #2426)\n- Tab bar clicks are now properly registered when using Ghostty in native fullscreen. (#796, #2736, thanks @HackAttack)\n- Prefix keybindings now disambiguate layout-aware shifted punctuation, so a shifted `\\` no longer triggers `prefix+|` on keyboard layouts where the same key produces both characters. (#2674)\n- Remote clients now continue redrawing at very large terminal sizes instead of freezing when a full ANSI frame exceeds the transport limit. (#2670)\n- Windows Git status refreshes now reuse repository configuration instead of repeatedly triggering security scans for WSL repositories. (#2643, #2688, thanks @Pimpmuckl)\n- Windows idle agent detection now shares process snapshots across panes, reducing CPU use in sessions with many Git Bash panes. (#2459, #2494, #2642, #2651, thanks @Pimpmuckl)\n- Embedded bare repositories now derive the correct repository name and worktree location. (#2657, #2660)\n- Root-repository workspaces now retain their saved labels across update restarts. (#2594, #2727)\n- Elevated Windows panes no longer expose PowerShell's administrator decoration as the terminal title. (#2632, thanks @Pimpmuckl)\n- Modal name inputs now anchor the host IME cursor to the text field instead of the pane behind the dialog. (#1755, #2569, thanks @kataokatsuki)\n- Session Navigator movement ignores modified `j`, `k`, and arrow keys instead of consuming unrelated pane input. (#1981, #2377, thanks @atomsbaza)\n- OpenCode panes now track the root conversation selected in their own TUI for native restore without adopting activity from attached clients. (#2450)\n- Server stop requests now bypass pane and API traffic, preventing busy sessions from blocking shutdown or admitting a client while shutdown is pending. (#2612)\n- Fish `Ctrl+Alt` keybindings now work in panes after legacy Alt-prefixed control bytes are decoded with both modifiers. (#2514)\n- Windows recent-history reads no longer perform redundant snapshots, restoring `recent` output while reducing read cost. (#962, #2474, thanks @Pimpmuckl)\n- The Windows installer now activates releases with an atomic directory swap, preventing interrupted updates from leaving an empty release directory. (#2356, #2530, thanks @Pimpmuckl)\n- `herdr config check` now reports unknown built-in theme names instead of silently accepting them. (#2452)\n- macOS `herdr --remote` clients now keep the accepted bridge socket blocking, preventing an immediate disconnect after the protocol handshake. (#2478, thanks @mathijshenquet)\n- Prefix keybindings now preserve Shift in WezTerm Kitty keyboard mode, so commands such as config reload no longer trigger their unshifted action. (#2435)\n- Pane applications now receive modifyOtherKeys releases and shifted alternate reports without dropped releases or leaked Ctrl+Tab sequences. (#2296, #2302, #2303)\n- Detaching now restores host keyboard reporting, preventing enhanced keyboard sequences from leaking into the shell after Herdr exits. (#2393, #2395)\n- Default mouse reports are decoded instead of leaking escape bytes into the focused pane. (#2309, #2312)\n- BEL characters emitted by pane programs now reach the outer terminal so its audible and visual bell settings can react. (#2453)\n- Stable direct installs, self-updates, and remote helper downloads now require and verify the SHA-256 digest published for each GitHub release asset.\n- `pane read` and `pane wait-output` now accept `--flag=value` and options before or after the pane ID. (#2183, thanks @KyleCo76)\n- `pane current`, `pane get`, and `pane layout --current` now resolve the calling pane instead of another client's focused pane. (#2297, #2298)\n- Configs containing the retired Herdr-written `ui.agent_panel_scope` setting no longer report it as an unknown key after upgrades. (#2292)\n- Claude Code confirmation prompts using `Enter to confirm \u00b7 Esc to cancel` now report `blocked` instead of `idle`. (#2268)\n- Kiro CLI prompts now have positive idle detection instead of remaining in an unknown state. (#2301, thanks @smileynet)\n- Cursor's Run Everything footer no longer produces a false blocked state. (#1763, #2220, thanks @Nagi-ovo)\n- Versioned Python agent wrappers such as `python3.13` are now detected. (#2188, thanks @plarson)\n- Pi state reporting now ignores RPC, JSON, and print-mode helper processes that are not interactive TUI sessions. (#2159, thanks @rhjoh)\n- Collapsed workspace and Agent rows keep their status and active indicators visible, including with ten or more workspaces. (#2216, #2239, #2382, thanks @ianks)\n- Sidebar agent lists keep scrolling when differently sized clients are attached to the same session. (#2255, thanks @aiworkflowpro)\n- The Session Navigator now searches renamed single-tab labels. (#2320)\n- New splits return focus to the pane they were opened from. (#2266, thanks @jondkinney)\n- Halfwidth Katakana voiced and semi-voiced marks now render in the correct cell. (#2257, thanks @kazunari-kamata)\n- Ctrl-clicking a URL no longer forwards its release after the browser takes host focus, preventing duplicate tabs. (#2290, #2291, thanks @kataokatsuki)\n- OSC 4 palette overrides now render with the requested color instead of forwarding the palette index. (#2162, thanks @hamidi-dev)\n- Host terminal appearance is re-queried when focus returns, keeping automatic light and dark themes current. (#2416, #2417)\n- The bundled and installable Herdr agent skill now matches this stable release's CLI and lifecycle behavior. (#2847)\n- `pane send-keys` and `agent send-keys` now preserve Shift when sending `shift+tab`, allowing agent permission modes to be cycled programmatically. (#1561, thanks @keinstn and @tomohisa)", - "protocol": 20, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-macos-aarch64", - "windows-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.2/herdr-windows-x86_64.zip" - }, - "sha256": { - "linux-x86_64": "976150a14d490c94b243ea2e1a7eb2dfb67f12e36b182db90936f6728e6aecf4", - "linux-aarch64": "f55610658e1c2e0d2aaef730b4b2ab885f7f8ba00285ab372bfb14f2e3d5b40d", - "macos-x86_64": "ab50262c8190cd7aa9056d249d255c08c328c3e8716de9cfa29db4f131b8e2c1", - "macos-aarch64": "a5d4f4d504d8b309c91f811050559300faba31258425f53c50852fc96f6ae574", - "windows-x86_64": "0ab3d0fe1434d55757997542b978c771d642987bb15a7130f4160f0db38821d5" - } - }, - "0.8.0": { - "notes": "### Added\n- Added `herdr --skill` to print the agent skill bundled with the running Herdr binary.\n- Added `ui.pane_scrollbars = false` to hide terminal pane scrollbars and reclaim their reserved column. (#2167)\n- Added `ui.tab_bar_position = \"bottom\"` to place the desktop tab row below terminal panes. (#2117)\n- Added live filtering to the keybind help with `/`, Backspace, and `Ctrl+U`. (#1825, #1832, thanks @corrius)\n- Added Windows support for `experimental.switch_ascii_input_source_in_prefix` with Korean IMEs. (#1802, #1823, thanks @joonhwan)\n- Added Grok CLI session reporting and native restore with `grok --resume <id>`. (#1800, #1807, thanks @carlesso)\n- Added Antigravity CLI session reporting and native restore with `agy --conversation <id>`. (#1011, #1571, #2087, thanks @ludoo)\n- Added automatic text history reads for idle alternate-screen agents, with the application viewport restored after collection.\n- Added `workspace.move_block`, the `workspace.reordered` event, and atomic worktree-group reordering. (#1694)\n- Added a Simplified Chinese README. (#1990, thanks @patrick-xin)\n\n### Changed\n- Experimental options are no longer exposed in the Settings TUI and remain available through the config file.\n- Agent status indicators now use the same static workspace marks across the sidebar, navigator, and mobile views, eliminating continuous spinner rendering while agents work.\n- Hidden pane output no longer triggers unnecessary TUI rendering.\n- Windows preview downloads now include Herdr and a modern app-local ConPTY runtime in one archive. (#1533, #1644, #1828)\n- Worktree parents and children now stay packed together in the sidebar, including while groups are reordered.\n- Public documentation now separates stable, preview, and immutable versioned release snapshots.\n- Repository and installation links now use `herdrdev/herdr` after the GitHub organization migration.\n- Relicensed Herdr from AGPL-3.0-or-later to Apache-2.0.\n\n### Fixed\n- Pane applications now receive semantic light/dark query responses and live Mode 2031 updates when the host appearance changes. (#714)\n- Remote attach now falls back to `sh` when the login shell cannot perform path discovery. (#1201)\n- PTY output continues to be read while pane input is temporarily blocked. (#1295)\n- Worktree CLI help and docs no longer advertise the redundant `--json` flag; worktree commands remain JSON-only and continue accepting the flag for compatibility. (#2171)\n- OpenCode 2 preview panes now appear as OpenCode agents and use the existing OpenCode status detection. (#2169)\n- Pane text copied through VS Code Remote Tunnels now reaches the viewing machine's clipboard instead of overwriting the remote host clipboard. (#2015)\n- Windows agent detection now follows Git Bash-launched agents across emulated `exec` process boundaries. (#2107)\n- Detached Windows servers and pane processes now survive logout from the OpenSSH session that started them. (#2008)\n- Windows `agent start` now launches agents without native arguments instead of timing out on an invalid empty PowerShell argument list. (#2072)\n- Headless servers now resume restored agent sessions without waiting for a TUI client to attach. (#2064)\n- Vibe and other Kitty-keyboard pane applications now receive shifted letters and punctuation when they request associated text. (#2020)\n- Kitty-keyboard pane applications now receive printable key releases without duplicate text input. (#1746)\n- Kitty graphics remain visible during host repaints. (#1628)\n- Pane applications now receive correct XTWINOPS terminal and cell-size query responses. (#835)\n- WSL clients query the host cell size when the terminal ioctl reports no pixels, keeping graphics sharp instead of using the 8x16 fallback. (#2146, #2160, thanks @WakaTaira)\n- Linux runtimes without terminal foreground process groups can opt into child-group agent detection with `HERDR_PROCESS_DETECTION=child-groups`. (#1982)\n- Installing the Herdr agent skill with the `skills` CLI no longer copies the entire repository. (#2022)\n- Nix builds now include the bundled agent skill required by `herdr --skill`. (#1889, #1890, thanks @olafkfreund)\n- Agent prompts now wait briefly after sending text before pressing Enter, preventing prompts from remaining in agent composers without starting a turn. (#1878)\n- Empty clipboard writes from pane applications no longer erase existing clipboard contents or show a copied confirmation. (#1893)\n- Plain mouse movement no longer triggers continuous full renders while preserving Herdr menu hover and pane application mouse tracking. (#1865)\n- Extended-button drags now preserve Herdr hover state while applications receive the drag.\n- `ui.copy_on_select = false` now retains drag and double-click word selections without copying; `Ctrl+C`, or `Cmd+C` when the host terminal forwards it, copies and clears the selection. (#1782)\n- Pane and agent read responses now report `truncated: true` when older terminal rows were omitted. (#1717)\n- Pane applications that query OSC 4 palette colors now inherit the host terminal palette. (#1752)\n- Ctrl-clicking a pane URL no longer forwards an unmatched mouse release to alternate-screen applications, preventing duplicate browser tabs. (#1761)\n- Known-agent integrations now leave pane ownership to confirmed process exit, so restarting Pi with the same saved session restores lifecycle state even with custom working UI. (#1648, #1792)\n- Nested or ephemeral Codex sessions no longer replace the owning pane's resumable session. (#1789, #1927, thanks @Pimpmuckl)\n- Pi RPC, JSON, and print processes no longer claim pane lifecycle state intended for Pi TUI sessions. (#2159, thanks @rhjoh)\n- Hermes state now comes from screen detection while its plugin reports resumable session identity, avoiding stale lifecycle authority from incomplete hooks.\n- OMP integration install, status, and uninstall now respect `PI_CONFIG_DIR` when `PI_CODING_AGENT_DIR` is not set, and installation refuses extension-directory collisions with Pi. (#1696)\n- OMP integrations now preserve Windows absolute session paths for native restore. (#2092, thanks @art-wiedzmin)\n- Claude integration updates preserve existing settings key order and formatting. (#2066)\n- Physical Escape key records on native Windows now bypass raw VT report framing, so pane applications receive Escape immediately and reliably. (#1736)\n- Native Windows key presses, grouped repeats, and releases now preserve their physical lifecycle and stay with the pane that received the initial press. (#2077)\n- Windows `pane send-keys` and `agent send-keys` now deliver semantic Escape as a complete key tap, preventing a following key from being interpreted as an Alt chord.\n- Shift+Enter now reaches native Windows pane applications with its modifier intact. (#1743, #1909, thanks @Pimpmuckl)\n- Ctrl+_ input bytes now decode as Ctrl+_ instead of Ctrl+-. (#2164, #2165, thanks @Sertug17)\n- Prefix and navigate modes now recognize non-US shifted keybindings while retaining legacy US punctuation support. (#1870)\n- Closing a non-focused workspace no longer changes the focused workspace. (#1328, #1877, thanks @yianL)\n- A background workspace that closes after its last pane exits no longer moves focus or hides the current workspace. (#1621, #1912, thanks @season179)\n- Directional pane focus now keeps Navigate mode active. (#1850, #1993, thanks @we11adam)\n- Closing a workspace's last tab through the CLI or API now closes the workspace like the TUI does. (#1760, #1899, thanks @season179)\n- Linked worktree workspaces retain their labels during Git metadata refreshes.\n- Clients repaint after transient terminal resizes instead of leaving stale or missing rows.\n- Repeated workspace Git discovery and foreground-cwd checks no longer block rendering or API handling. (#1838, #2206)\n- Relative plugin commands now resolve from the plugin root. (#1949)\n- Windows installation preserves inherited `PATH` and related environment variables. (#1947)\n- Windows agent process discovery preserves the owning parent agent across wrapper processes. (#1514)\n- The Rose Pine `surface_dim` color remains visible when the outer terminal uses a matching theme. (#1946, #2002, thanks @brabli)\n- CLI socket commands now report a clear `server_not_running` error instead of a raw I/O error. (#1941, #1963, thanks @season179)\n- Non-UTF-8 CLI arguments now produce a usage error instead of panicking. (#2207, thanks @VialFlorian)\n- Copy-mode `e` now crosses long soft-wrapped CJK lines when a read window ends on a wide glyph. (#2145, thanks @kiakiraki)\n- Clients restore terminal state when they receive SIGHUP or SIGTERM. (#2041, thanks @MattJColes)\n- Windows now shows `system` notifications and completes MP3 notification sounds without leaving PowerShell players waiting for a timeout. (#1330)", - "protocol": 19, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.8.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.8.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.8.0/herdr-macos-aarch64" - }, - "sha256": { - "linux-x86_64": "b872ea7e40fa2cb17e857ac9b62b1bf26db7b403c622f5d2f3f5b35f6e9acd28", - "linux-aarch64": "f647ac66468d9efbc642fe534fb284468f0aea60641606fc008dfc0d82a3ca87", - "macos-x86_64": "77cb5afd6c8fcaaaf3bc28e474ec01c209331ad08094e20d7f8aa9b0bb78d649", - "macos-aarch64": "d53a9f93fccfdfcc55632927bf51002f5add0aa7990bcdf508ffbd84ac658178" - } - }, - "0.7.5": { - "notes": "### Breaking Changes\n- Installed and linked plugins, including their enabled state, are now global to the current user instead of isolated by Herdr session. Plugins installed only in a named session on Herdr 0.7.3 must be installed or linked again. (#1174)\n\n### Added\n- Added a live-agent CLI facade with named `start`, atomic `prompt`, logical `send-keys`, and server-owned `wait` workflows. Agent startup targets an existing pane without changing topology, validates the requested interactive agent kind and strict agent name, and accepts native arguments after `--`.\n- Added transient declarative Agent view queries through `agent.view.set/clear`; filtered and sorted views now define sidebar, mobile, mouse, and agent-keybind navigation order.\n- Added one-shot plugin `[[startup]]` hooks for restoring plugin-owned state after server startup and live handoff.\n- Added per-token foreground, bold, and dim styling to expanded Space and Agent sidebar row layouts.\n- Added `ui.sidebar_start_collapsed` to launch Herdr with the sidebar collapsed. (#1463)\n- Added `ui.prompt_new_workspace_name` to ask for a workspace name before interactive TUI creation.\n- Added macOS support for the `HERDR_AGENT=<agent>` foreground-process hint, allowing agents hidden behind host-visible wrappers such as `nono` to use the named agent's screen manifest. (#679)\n\n### Changed\n- Agent commands now accept only a unique live agent name or the pane ID currently hosting that agent. Names are cleared when the occupant exits, is released, or is replaced. The old top-level `wait` commands were replaced by `agent wait` and `pane wait-output`, and `agent send` was replaced by `agent send-keys`.\n- The session navigator now uses connected tree glyphs, groups matches by workspace, and automatically selects the first result when a search begins. (#1611)\n\n### Fixed\n- CLI requests now return a machine-readable `protocol_mismatch` error when the client and server protocols differ, while recovery commands remain available. (#1435)\n- Linux sound notifications now terminate and reap audio players that do not exit, preventing unavailable audio from leaving CPU-bound `mpg123` processes behind. (#1622)\n- Oversized bracketed text pastes are now rejected with a client-local notification instead of disconnecting the client. (#1665)\n- Agent prompt waits now report `agent_prompt_stalled` after five seconds without an observed state change instead of waiting indefinitely after an ineffective submission.\n- `herdr config check` now reports unknown config keys with their full paths instead of treating ignored typos as valid configuration. (#1573)\n- Codex panes with customized static terminal titles now fall back to the live working footer instead of remaining idle, while OSC activity remains preferred. (#1563)\n- Grok panes now preserve working and blocked state from terminal signals and pinned background-work status instead of falling back to idle mid-turn.\n- OpenCode lifecycle reports are now serialized so out-of-order plugin events cannot leave an idle pane marked working. (#1519)\n- Kimi question prompts now report blocked until the user answers or dismisses them.\n- Pi lifecycle reporting now uses settled events, preventing transient message boundaries from publishing an idle state mid-turn.\n- The Pi, OMP, OpenCode, and Kilo Code integrations can now be installed on Windows and report lifecycle state and native session identity through Herdr's named-pipe API. (#1531)\n- Named agent prompts now honor live bracketed-paste mode before sending Enter, preserving OpenCode text such as `A != B` instead of triggering shell mode. (#1525)\n- New panes, tabs, layouts, and workspaces using `new_cwd = \"follow\"` now inherit the foreground process-group leader's working directory instead of an unrelated helper process directory. (#1472)\n- Cached pane working directories no longer trigger repeated filesystem checks, avoiding slow sidebar rendering on network filesystems such as Ceph. (#1603)\n- Windows foreground-process snapshots are now shared across panes, reducing idle CPU use in sessions with many panes. (#1158)\n- Terminal diff streams now batch contiguous writes, reducing the visible wave effect while scrolling pane history. (#283)\n- A standalone Escape arriving beside another key is now preserved as its own input instead of being combined into a fabricated Alt chord. (#541)\n- Pane viewports that were following live output now continue following after a resize.\n- Mouse selections now remain visible when `ui.copy_on_select = false` while clipboard writes stay disabled. (#1471)\n- Workspace close confirmation now shows the current workspace name instead of a stale or unrelated label. (#1364)\n- Plugin command arrays now preserve whitespace-only arguments. (#1594, #1613)\n- Plugins can now be installed or linked while no Herdr server is running. (#1670)\n- Remote attach now discovers Herdr installed in mise's canonical tool path before offering to install a sidecar binary. (#1201)\n- Noninteractive update, plugin, integration, sound, custom-command, and Git subprocesses no longer flash console windows on Windows. (#1468)\n- Live handoff now preserves installed plugins and no longer lets the next plugin installation overwrite the existing registry. (#893)\n- `herdr agent wait` now returns `agent_not_running` promptly when its target pane closes instead of waiting for the full timeout. (#1439)\n- Pane graphics streams now shut down cleanly when a client disconnect races stream teardown.", - "protocol": 17, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.5/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.5/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.5/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.5/herdr-macos-aarch64" - } - }, - "0.7.4": { - "notes": "### Added\n- Added session-modal popup floating terminal panes for `type = \"popup\"` custom command keybindings and plugin panes, with optional cell or percentage sizing and no changes to the tiled tab layout. (#1125)\n- Added `ui.copy_on_select` to disable automatic clipboard copying after mouse selection while keeping the selection visible.\n- Added configurable row layouts for expanded Space and Agent sidebar entries, including built-in display tokens, per-agent overrides, custom metadata tokens, and pane/workspace metadata reporting through the CLI and socket API.\n- Added independent `row_gap` settings for expanded Space and Agent sidebar entries.\n- Copy mode now supports literal smart-case search with `/` and `?`, repeating with `n` and `N`, match highlighting, and tmux-style cross-line `w`/`b`/`e` word motions. (#1230)\n- Added Maki agent support. (#1301, #1302, thanks @tontinton)\n- Added a searchable, version-matched configuration reference and a troubleshooting guide covering duplicate terminal key events, modified-arrow shell bindings, updates, remote access, and logs. (#1116, #1370)\n\n### Changed\n- Expanded Space and Agent sidebar entries now use a packed layout by default; set the corresponding `row_gap` to `1` to restore the previous spacing.\n- Refreshed the bundled Herdr agent skill for current public workspace, tab, and pane ids and the current CLI/API workflow. (#1297)\n- Expanded Japanese and Simplified Chinese CLI documentation with shell completion setup and API schema usage. (#1151)\n\n### Fixed\n- Collapsed Agent sidebar rows now follow the same ordering and click targets as the expanded panel, and their shortcut numbers are assigned by visible list position instead of repeating across workspaces. (#1168, #1344)\n- Shifted indexed bindings such as `prefix+shift+1..9` now match terminals that report the corresponding punctuation characters. (#1184)\n- Plugin-driven tab renames now immediately refresh tab-bar geometry and labels. (#1111, #1179, thanks @kovalov)\n- New tabs, splits, layouts, and workspaces configured to follow the foreground directory now start from the focused pane's current working directory. (#1245)\n- Amp, Codex, and Claude Code detection now recognizes current active-turn UI variants, including reordered Codex title spinners and Claude `/btw` turns. (#1208, #1281, #1366)\n- Pi lifecycle state now reanchors after native session replacement, avoiding working panes that remain idle or tied to an abandoned session. (#943, #1189, thanks @dmmulroy)\n- OMP lifecycle reports are now retried when startup races drop the first report. (#1310)\n- WSL now uses Herdr's drawn cursor by default, matching the native Windows workaround for host cursor flicker. (#930)\n- Live handoff now preserves explicit named-session socket paths, waits for slower server shutdowns, and flushes API responses before the old server exits. (#1180, thanks @dvic)\n- The Windows installer no longer rewrites an existing config file or creates a duplicate onboarding line during first-run setup. (#1162)\n- Config diagnostics now reach CLI-only and attached-client startup paths reliably and clearly identify fallback configuration behavior.\n- Detached custom command children are now reaped after exit instead of accumulating zombie processes. (#1360)\n- Renamed single tabs now remain visible in the Agents sidebar instead of losing their tab label. (#1369)\n- Documentation search results are now scoped to the active locale and stable or preview channel.\n- Horizontal wheel and trackpad events now reach pane applications that enable mouse reporting. (#1349)\n- Copy mode `$` and End now stop at the final visible character on the row instead of jumping to the pane edge. (#1405)\n- Split SGR mouse reports are now reassembled across input reads, and a preceding standalone Escape is preserved instead of being swallowed or leaked as mouse bytes. (#1334, #1382)\n- Linux foreground-process discovery now stays within Herdr pane process trees instead of scanning unrelated host processes, reducing CPU use on busy multi-user systems. (#1399)\n- Single-codepoint emoji chosen from the Windows emoji picker now reach panes when WezTerm's kitty keyboard support sends them as CSI-u events with associated text. (#1404)\n- Outer-terminal focus gained and lost reports now reach the focused pane when its application enables focus reporting, restoring Neovim file autoreload and other focus-aware terminal behavior. (#1337)\n- Native Windows servers now detach from the terminal console that launched them, so closing WezTerm, Windows Terminal, or another host terminal no longer stops persistent pane processes. (#1329)\n- Windows API clients now remain connected while waiting for initial named-pipe request bytes, so `status server`, `api snapshot`, and other socket commands no longer intermittently fail with BrokenPipe. (#1279)\n- `herdr --remote` now installs remote helper binaries without routing the binary stream through a multiline `/bin/sh -c` command, fixing installs for non-POSIX login shells such as xonsh. (#1203, thanks @nhumrich)", - "protocol": 16, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.4/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.4/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.4/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.4/herdr-macos-aarch64" - } - }, - "0.7.3": { - "notes": "### Fixed\n- The session navigator now keeps the active search query when leaving and re-entering search focus, and its footer now shows shortcuts for the current input mode. (#1115, #1140, thanks @liby)\n- Re-focusing an already-focused done agent or pane through the socket API now marks it seen instead of leaving stale done status in API responses.\n- Windows foreground-process detection now ignores cyclic process-parent snapshots instead of growing memory until the server aborts. (#1083)\n- Terminal redraws now hide the cursor inside synchronized output, reducing focused-pane cursor flicker during active redraws. (#967)\n- Headless render streams no longer scan visible plain-text URLs during rendering, reducing redraw work while preserving OSC 8 hyperlink metadata.\n- The workspace picker once again honors navigate-mode workspace up/down keys, including custom bindings, after `prefix+w`. (#1149)", - "protocol": 16, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.3/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.3/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.3/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.3/herdr-macos-aarch64" - } - }, - "0.7.2": { - "notes": "### Added\n- Added MastraCode integration support with lifecycle state reports and native thread restore. (#337, #788, thanks @wardpeet)\n- Added `ui.sidebar_collapsed_mode = \"hidden\"` to make a collapsed sidebar use zero width while keeping the existing compact rail as the default. (#842)\n- Added `herdr completion <shell>` / `herdr completions <shell>` to generate shell completion scripts for bash, elvish, fish, PowerShell, and zsh. (#435)\n- Added `session.snapshot` to bootstrap client runtime state in one socket API response before subscribing to events.\n- Added `herdr api schema` to inspect the bundled socket API schema, with `--json` for the full JSON Schema document and `--output PATH` for file output.\n- Added `layout.updated` socket events so protocol clients can keep tab layout snapshots current after pane split, resize, swap, move, zoom, and layout mutations.\n- Added pane scroll metrics to pane socket API responses and `pane.scroll_changed` subscriptions for clients that need to show when a pane is scrolled back.\n- Added `herdr terminal session observe` for read-only live ANSI terminal streams that bridge processes can consume as newline-delimited JSON.\n- Added `herdr terminal session control` for bridge processes that need live ANSI frames plus input, resize, scroll, release, and takeover authority.\n- Added `ui.hide_tab_bar_when_single_tab` to hide the tab row when a workspace has one tab. (#448)\n- Added Japanese and Simplified Chinese website docs.\n\n### Changed\n- The mobile switcher now starts from an agents-first summary and renders worktrees as a tree, making narrow terminals easier to scan.\n- macOS prefix input-source switching now runs on the foreground client, so non-Latin input sources are restored reliably after prefix mode. (#774, #1016, thanks @ppggff)\n- Nix packaging now uses `xcbuild` instead of custom Apple SDK wrappers for Darwin builds. (#995, thanks @arunoruto)\n\n### Fixed\n- Windows clients now send shifted punctuation such as `!`, `?`, and `:` as literal text to Kitty-keyboard-mode pane apps, fixing Kiro CLI TUI prompts while preserving modified key chords. (#1066, #1105)\n- Alt-Shift letter chords are now preserved instead of being collapsed into plain uppercase input. (#1088)\n- Antigravity background-task waits are now detected even when the UI does not show a `/tasks` hint. (#755)\n- `herdr --remote` now prints clean remote attach failures and SSH authentication guidance instead of Rust Debug-formatted I/O errors when SSH authentication is denied. (#1034)\n- `herdr server stop` now stops Windows named-pipe servers instead of failing with `named pipes do not support I/O timeouts`. (#1113)\n- `herdr server stop` now waits until both server sockets are unreachable before returning, avoiding an immediate first-start failure when restarting right after replacing the binary.\n- macOS `herdr --remote` clients now bridge Finder-dropped image files to the remote pane instead of forwarding the local file path as typed text. (#828)\n- Grok Build agent detection now tracks the current Grok Build UI: panes report working while responses, tools, and subagents run, and blocked on permission prompts and question dialogs, instead of falling back to idle mid-turn. (#1017, #1055, thanks @TonyxSun)\n- GitHub Copilot CLI detection now recognizes the newer Esc interrupt prompt as working. (#1119, #1120, thanks @LaneBirmingham)\n- Unix local Herdr clients no longer treat empty bracketed paste as a clipboard-image bridge; `herdr --remote` keeps using it for local-desktop image paste over SSH. (#986)\n- Custom command keybindings now run through `cmd.exe /d /c` on Windows instead of `/bin/sh`, so `type = \"pane\"` and `type = \"shell\"` bindings can launch native Windows commands. (#1041)\n- Plain PageUp/PageDown now reach primary-screen pager apps such as `less -X` and Git diff when they enter application cursor mode, while shell transcripts still use Herdr pane scrollback. (#953)\n- Copy mode now supports Ctrl-page navigation, keeps the Herdr prefix key available while copying, and restores the copy context correctly after prefix commands. (#681, #885, #1092, thanks @reobin)\n- `prefix+e` scrollback editor panes now open on Windows without trying to run `/bin/sh`; Windows uses `VISUAL`, then `EDITOR`, then `notepad.exe` as the fallback editor. (#914)\n- `herdr pane split --current` now resolves to the calling Herdr pane instead of the UI-focused pane when run inside a pane. (#902)\n- Native Windows clients running inside Alacritty now preserve mouse reports and `ctrl+j` input instead of leaking mouse escape sequences into panes. `shift+enter` remains dependent on whether the outer terminal reports it as a distinct modified Enter key. (#792)\n- Windows clients now preserve bracketed paste, Backspace, modifier-only keys, host cursor drawing, native clipboard copies, recent pane reads, and wait connections across the native input path. (#670, #795, #907, #920, #930, #962, #963, #1067)\n- New tabs and workspaces now follow the focused pane's current directory more reliably, including PowerShell panes that report cwd through prompt shell integration on Windows. (#912, #919)\n- Pi and OMP integration state now survives internal session reloads, recovers after resumed sessions such as `omp -c`, and reports Ask/tool approval waits as blocked instead of leaving the pane working or stuck on the previous session. (#800, #879, #984, thanks @dmmulroy)\n- Pi state socket reports are now retried, reducing stale sidebar state when the report races server startup. (#1049)\n- OpenCode now reports subagent permission prompts as blocked and handles object-form `session.status` events. (#838, thanks @soar)\n- Remote attach now discovers compatible Homebrew, mise, and Nix profile installs before offering to install a sidecar binary to `~/.local/bin/herdr`. (#840)\n- `herdr --remote` sessions now keep the remote server in its own login-independent session and preserve compatible running servers after helper binary updates, so network drops should disconnect only the client instead of killing remote panes.\n- `herdr --remote` now reuses one OpenSSH connection across setup probes, installs, server checks, and the final bridge when `[remote].manage_ssh_config` is enabled, so password-based hosts prompt once instead of once per setup command. (#888)\n- Foreground agent session reports can now replace stale saved session references, so resumed panes do not stay tied to an older agent session. (#943)\n- Kitty graphics panes now repaint streaming image updates reliably and delete replaced host images instead of leaking them. (#947, #948, thanks @DevSrSouza)\n- Pane apps that query OSC 12 cursor color now receive a response. (#806)\n- ANSI undercurl styles now render in panes. (#895)\n- CJK pane border labels, compact keybinding help ranges, and active auto-named tabs now measure by display width, avoiding broken alignment and unreadable labels. (#799, #810, #817, #829)\n- Ctrl+/ is now encoded as Ctrl+_, matching terminal expectations for pane apps. (#847)\n- PowerShell panes now stay alive after agent Ctrl+C. (#860)\n- SGR mouse reports no longer leak into pane input after host-side handling. (#939)\n- Wrapped pane links now preserve their target instead of being truncated across soft-wrapped lines. (#1098)\n- Linux foreground process-group scans are cached, reducing idle CPU in large sessions. (#936)\n- Session autosaves now run off the main loop, reducing UI stalls in busy sessions.\n- Worktree removal now focuses the parent workspace after closing the worktree workspace. (#1004)\n- Closing a tab from the context menu now exits the menu cleanly. (#945)\n- Copy feedback now stays visible above retained pane updates. (#555)\n- Windows ARM64 installer fallback now works when the normal checksum path is unavailable. (#897)", - "protocol": 16, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.2/herdr-macos-aarch64" - } - }, - "0.7.1": { - "notes": "### Added\n- Added `[update].version_check` and `[update].manifest_check` so background Herdr version checks and remote agent-detection manifest checks can be disabled independently. Manual `herdr update` and bundled/local detection manifests still work when the background checks are disabled. (#677)\n- Added `HERDR_AGENT=<agent>` as a Linux foreground-process hint for agents hidden behind wrappers such as VMs, Bubblewrap, or `fence`, allowing Herdr to use the named agent's screen manifest when `/proc` cannot expose the real command. (#679)\n- Added `ui.pane_borders` and `ui.pane_gaps` to make split pane dividers and spacing configurable. (#271)\n\n### Changed\n- Removed the Agents panel workspace/all filter. The panel now always shows all agents, defaults to grouped-by-space ordering, and can switch to priority ordering with `ui.agent_panel_sort = \"priority\"`. (#318)\n- User keybindings now displace conflicting built-in defaults during config load, so overriding a default binding no longer leaves both actions attached to the same key. (#747)\n- Worktree creation now checks out an existing local branch when the requested branch already exists instead of failing by trying to create it again. (#729)\n- Worktree operations started through the socket API and plugin/UI flows now defer long-running Git work until the app runtime can drive it, keeping clients responsive and preserving plugin lifecycle events for worktree-created panes. (#657, #662, #686)\n- OMP, OpenCode, Pi, Devin, and other official hook integrations now scope lifecycle and session reports to the intended root agent process more reliably, reducing stale or cross-process session adoption after restarts, nested commands, and new sessions. (#614, #712, #719, #765)\n\n### Fixed\n- Windows Terminal multiline text paste now reaches pane apps as one bracketed paste, so OMP, Pi, and similar prompts no longer submit each pasted line separately. Plain Esc, Shift+Enter, mouse, focus, resize, and Unicode paste handling are preserved on the Windows client path. (#670)\n- Local Herdr clients no longer treat raw `Ctrl+V` as a clipboard-image paste trigger, so pane apps such as Vim and Neovim receive block-visual `Ctrl+V` even when the desktop clipboard contains an image. `herdr --remote` keeps `keys.remote_image_paste = \"ctrl+v\"` by default. (#647)\n- Herdr now refreshes cached host terminal colors when terminals report a light/dark color-scheme change, so pane apps that query OSC 10/11 no longer need detach/attach to see updated default colors. Opt-in `[theme].auto_switch` can also switch Herdr's own UI between configured `dark_name` and `light_name` themes. (#675)\n- Full-lifecycle hook agents can now recover when an old release/report sequence belongs to a previous agent generation. Herdr keeps process-exit validation active under lifecycle authority and re-anchors hook sequence guards after fresh session references or proven process exits. (#684)\n- OMP now reports a native session reference, so an OMP pane reappears in the Agents panel after exiting and rerunning `omp` in the same pane, and Herdr can resume it with `omp --resume=<session>`. Previously the released lifecycle hook stayed suppressed until a server restart. (#614)\n- Host terminal color query (OSC 10/11) replies that arrive split at their escape introducer no longer leak as text like `11;rgb:...` into the focused pane, most visible when launching agents that probe terminal colors on startup. (#549)\n- Long CJK Git branch names in the sidebar now truncate by display width instead of overflowing or cutting at the wrong cell boundary. (#644)\n- Temporary pane commands launched from API flows no longer steal focus from the previously focused pane after they finish. (#658)\n- Root agent session restore now ignores child process reports that would otherwise overwrite the saved session for the owning pane. (#712)\n- Kitty file-transfer media queries are now answered, allowing pane apps that rely on kitty graphics file support to detect image/file media capability correctly. (#732)\n- Idle or slow clients no longer block server writes to other clients while the blocked client is waiting for output. (#726)\n- GitHub Copilot CLI `ask_user` accept prompts are now detected as blocked so the Agents panel shows that the pane is waiting for input. (#725)\n- Pane reads now skip wide-character spacer cells, avoiding duplicated or malformed output around double-width characters. (#698)\n- Split pane border intersections now use the active pane color consistently. (#742, thanks @cullendotdev)\n- The Windows installer checksum fallback no longer depends on `Get-FileHash`, improving compatibility with constrained PowerShell environments. (#751)\n- Pi launched through npm wrappers on Windows is now detected as Pi instead of a generic wrapped process. (#754)\n- Windows builds now force the system ConPTY path through a vendored `portable-pty` patch, avoiding the bundled-path startup failure seen in affected Windows environments. (#761)\n- Key release events that fall back to encoded input no longer double-send text into pane apps. (#769)\n- Remote clients now allow a longer initial handshake, improving `herdr --remote` startup over high-latency links. (#753)", - "protocol": 14, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.1/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.1/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.1/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.1/herdr-macos-aarch64" - } - }, - "0.7.0": { - "notes": "### Added\n- Added local plugin v1 support with `plugin.link/list/unlink/enable/disable`, manifest-declared actions, event hooks, managed plugin panes, link handlers, command logs, keybinding integration, and authoring docs under Preview docs.\n- Added `herdr plugin install <owner>/<repo>[/subdir...]`, `plugin uninstall`, source metadata in `plugin.list`, offline registry fallback, and a human-readable default `plugin list` with `--json` for scripts.\n- Added `herdr plugin config-dir <id>` and automatic plugin config/state directory creation so plugin setup docs can point users at a stable config path.\n- Added Devin CLI automatic detection plus `herdr integration install devin` hooks that report session ids for restore with `devin --resume <id>`. Devin state remains screen-detected because Devin hooks do not cover every permission cancellation and user interrupt transition. (#606, #622, thanks @minatoaquaMK2)\n- Added supporting plugin host APIs for `pane.current`, `pane.process_info`, `client.window_title.set/clear`, `layout.export/apply`, plugin pane placement, plugin invocation context/env injection, and plugin pane ownership across `pane.move`.\n- Added `pane.move` and `herdr pane move` to relocate a running pane into another tab, a new tab, or a new workspace without restarting its terminal process. (#299)\n- Tabs containing a zoomed pane are now marked in the tab bar so the zoom state is visible from other tabs.\n\n### Changed\n- Bumped the client/server protocol version to 14 for `pane.move` compatibility. (#299)\n- Public workspace, tab, and pane ids are now short stable handles such as `w1`, `w1:t1`, and `w1:p1`; closed tab and pane ids no longer retarget later resources. (#569)\n\n### Fixed\n- `pane.send_keys` and `pane.send_input.keys` now accept Herdr key-combo strings such as `ctrl+h`, `ctrl+j`, `ctrl+k`, and `ctrl+l`. (#613, thanks @dmmulroy)\n- Config startup and reload now warn about unknown top-level table sections, including a `[toast]` hint that points to `[ui.toast]`, instead of silently ignoring them.\n- Claude Code session restore now accepts real `/clear`, `/resume`, and compacted session identity changes while still ignoring nested `claude -p` startup sessions that inherit the pane environment. (#620)\n- Auto-named tab labels now stay compact after closing, moving, or creating tabs while public tab ids remain stable.\n- F1-F4 key presses sent as `ESC[11~` through `ESC[14~` now reach pane apps instead of being dropped. (#574)\n- Numeric keypad keys sent through the kitty keyboard protocol now enter their digits and operators instead of being dropped. (#570)\n- Pane resize keybindings now shrink panes again instead of only being able to grow them. (#562)\n- Windows pane cursor rendering is now stable instead of showing a misplaced or flickering cursor. (#556)\n- Tab identity is now preserved across restored sessions.\n- Idle panes now poll their PTY less frequently, reducing CPU use while sessions are inactive.\n- Captured pane URL clicks, including plugin link handlers, now use Ctrl-click on macOS too because captured terminal mouse reports do not expose Cmd-click separately from plain click. (#307)", - "protocol": 14, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.7.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.7.0/herdr-macos-aarch64" - } - }, - "0.6.10": { - "notes": "This is a hotfix release for v0.6.9. See the v0.6.9 notes for the full feature release.\n\n### Fixed\n- Lifecycle-authority agent integrations such as Pi and OpenCode no longer trigger a repeated detection reset loop that could flood logs, drive high CPU, and make the UI lag or stop responding. (#560, #565, thanks @dzevs)", - "protocol": 13, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.10/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.10/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.10/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.10/herdr-macos-aarch64" - } - }, - "0.6.9": { - "notes": "### Fixed\n- Copy mode page scrolling now stops at the same top and bottom boundaries as normal pane scrolling instead of overshooting or getting stuck near the edges. (#459, #460, thanks @reobin)\n- Clipboard-copy feedback no longer stays visible after the related selection state has gone stale. (#443)\n- The session navigator now uses live workspace labels, so renamed workspaces and cwd-derived labels stay current while navigating. (#377)\n- Hermes Agent integration installs now preserve flat plugin-list settings instead of rewriting them into nested lists. (#479)\n- Host-terminal focus redraws now stay pending until the client can send them, so panes refresh after focus returns even when redraw delivery was briefly busy.\n- Numeric keypad keys that send VT100 application-keypad escape sequences now enter their digits and operators instead of being dropped. (#493)\n- Codex panes now stay marked working when the live status header uses reasoning-summary text such as `Investigating code output` instead of the literal `Working` label. (#501)\n- Codex blocker detection now ignores stale prompt text outside the live prompt region, reducing false blocked states from old scrollback.\n- Native pane URL clicks now use Cmd-click on macOS and Ctrl-click on other platforms. (#307)\n- Worktree open, create, and remove actions now work from bare repositories instead of assuming a normal checkout. (#497)\n- Pane mouse handling no longer sends empty PTY writes for mouse events that produce no terminal input. (#496)\n- Pane output now renders flag emoji and other multi-codepoint grapheme clusters as complete symbols instead of blank cells. (#243)\n- Starting Herdr with no restored workspaces, or closing the last workspace, now opens a default workspace instead of leaving the client on an empty screen where direct keybindings such as `cmd+n` were shown but ignored. (#366)\n- Resizing restored panes no longer aborts the server when libghostty-vt reflows a terminal whose pre-resize cursor row is past the new height. (#465)\n- Full-screen TUIs such as Neovim now receive resize-generated terminal responses after Herdr internal pane resizes, so grown panes redraw without waiting for extra input. (#471)\n- Nested agent session reports from child terminals no longer overwrite the owning pane's restored agent session id. (#511)\n- Headless servers now avoid repeated scrollback rendering work for inactive panes, reducing CPU in large sessions. (#512)\n- Mouse-click handling now respects `ui.prompt_new_tab_name`, so mouse-created tabs follow the same naming prompt setting as keyboard-created tabs. (#521, thanks @imrajyavardhan12)\n- Pasting now works in modal text inputs, including rename prompts, command prompts, and worktree dialogs. (#302)\n- Linux clipboard image reads now validate image payloads before accepting them, preventing malformed clipboard data from reaching pane image paste flows. (#534)\n\n### Added\n- Added remote auto-updates for agent detection manifests, with per-agent validation, local override precedence, `herdr server agent-manifests` diagnostics, and explain output showing remote manifest status.\n- Added `herdr server update-agent-manifests` to fetch remote agent detection manifests immediately, reload the running server, and print the updated manifest status.\n- Added `herdr agent explain` to show the manifest source, matched rule, evaluated matcher and region evidence, visible evidence flags, skipped-update reason, and idle fallback reason for live panes or saved screen fixtures.\n- Added `herdr integration install kimi` for Kimi Code CLI hooks that report lifecycle state and session ids through Herdr's socket API. When native agent session restore is enabled, Herdr can resume Kimi panes with `kimi --session <id>`. (#431, #463, thanks @wbxl2000)\n- Added `herdr integration install droid` for Factory Droid hooks that report session ids through Herdr's socket API. When native agent session restore is enabled, Herdr can resume Droid panes with `droid --resume <id>`.\n- Added `herdr integration install kilo` for Kilo Code CLI plugins that report lifecycle state and session ids through Herdr's socket API. When native agent session restore is enabled, Herdr can resume Kilo panes with `kilo --session <id>`.\n- Added `herdr integration install cursor` for Cursor Agent CLI hooks that report session ids through Herdr's socket API. When native agent session restore is enabled, Herdr can resume Cursor panes with `cursor-agent --resume <id>`. (#506, thanks @udirom)\n- Added directional pane swap with `prefix+shift+h/j/k/l`, a pane context-menu swap action, pane layout/neighbor/edge/focus/resize socket APIs, matching CLI commands, and optional `pane split --ratio` support. (#330, #421)\n- Added `herdr pane zoom` and the `pane.zoom` socket API to toggle, set, or clear tab-local pane zoom from scripts and integrations.\n- Added toast ergonomics controls for delayed agent notifications, in-app toast placement, copied-to-clipboard feedback, and the `notification.show` socket API with `herdr notification show` and optional `none`, `done`, or `request` sounds. (#486)\n\n### Changed\n- OpenCode installed with the current Herdr plugin now reports lifecycle state directly instead of relying on screen manifest detection. Kimi Code CLI `0.14.0` or newer now reports full lifecycle state through hooks, including interrupts. Droid and Qoder CLI now report native session identity while leaving lifecycle state to screen manifest detection.", - "protocol": 13, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.9/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.9/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.9/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.9/herdr-macos-aarch64" - } - }, - "0.6.8": { - "notes": "This is a hotfix release for v0.6.7, prioritizing a server-crash fix for panes that print complex Unicode or emoji output.\n\n### Fixed\n- Fixed a Herdr server crash triggered by pane output containing complex Unicode, emoji, or decomposed accent graphemes. Affected sessions could lose running pane processes or crash again after restore if the same saved pane output was replayed. (#453)\n- Direct installs managed by mise now update through the mise install path instead of failing to replace the active binary.\n- Claude Code panes that are actively thinking or streaming no longer flicker to blocked because of custom status text. (#409)\n- Claude Code panes now detect running shell-command status more reliably.\n- OpenCode installed through pnpm is now detected as `opencode` instead of being missed because the packaged executable is named `opencode.exe`. (#447)\n\n### Added\n- Added opt-in macOS input-source switching during prefix mode with `experimental.switch_ascii_input_source_in_prefix`, so users typing with a non-Latin IME can run prefix commands through an ASCII-capable input source and return to the previous input source when prefix mode ends. (#400, #434, thanks @sf-jin-ku)", - "protocol": 12, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.8/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.8/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.8/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.8/herdr-macos-aarch64" - } - }, - "0.6.7": { - "notes": "### Added\n- Added a compact collapse control to the expanded sidebar so mouse users can collapse and expand the sidebar from visible controls. (#278, #291, thanks @turgaybulut)\n- Added an opt-in preview update channel with `herdr channel set preview`, `[update].channel`, automated preview manifests, and GitHub prerelease publishing for users who want fixes before stable releases as Herdr transitions toward less frequent, more stable releases.\n- Added a remote SSH bridge keepalive fallback. `herdr --remote` now generates a temporary SSH config that includes the user's SSH config first, then adds `ServerAliveInterval` and `ServerAliveCountMax` only when the user has not already configured keepalives. Set `[remote].manage_ssh_config = false` to disable this. (#354, #355, thanks @SunskyXH)\n- Added `ui.right_click_passthrough_modifier` so a configured modifier such as `ctrl` can forward right-click hold and drag gestures to mouse-reporting pane apps while normal right-click still opens Herdr's pane menu. (#148)\n- Added Kilo Code CLI automatic detection for idle, working, and blocked terminal states. (#270)\n- Added `herdr integration install copilot` for GitHub Copilot CLI hooks that report prompt, tool, post-approval progress, permission, `ask_user`, `exit_plan_mode`, idle, session-exit state, and session ids through Herdr's socket API. When native agent session restore is enabled, Herdr can resume Copilot panes with `copilot --resume=<id>`. (#232, #386, thanks @LaneBirmingham)\n\n### Changed\n- Native agent session restore is now enabled by default for supported panes with current official integrations. Set `[session] resume_agents_on_restore = false` to disable it.\n- Claude Code, Codex, and OpenCode integrations now report session identity only. Native state for those agents comes from Herdr's screen detection, while Pi, OMP, GitHub Copilot CLI, Hermes Agent, Qoder CLI, and custom socket integrations can still report state.\n\n### Fixed\n- Large long-running sessions no longer hit the frame-streaming crash fixed by the vendored libghostty-vt update. (#276)\n- Copy mode now preserves linewise selection after `shift+v` while moving the cursor. (#360, #389, thanks @reobin)\n- Leaving copy mode now restores the previous scroll position, or returns to the bottom when copy mode started at the bottom. (#398, #410, thanks @reobin)\n- Git branch labels now resolve correctly in repositories that use Git's reftable ref format instead of showing `.invalid`. (#384, #423, thanks @LaneBirmingham)\n- The official Nix flake now builds on macOS by providing Darwin SDK discovery helpers and Darwin cctools to the vendored libghostty-vt build. (#405, #407, thanks @DeevsDeevs)\n- Commands launched after `--`, such as `herdr agent start ... -- opencode --session <id>`, now preserve child argv flags instead of parsing them as Herdr flags. (#383)\n- Pane apps that request any-motion mouse tracking now receive hover/move events, making Textual-style TUI mouse interaction more reliable inside Herdr. (#419)\n- Claude Code background-agent wait text in scrollback no longer keeps an idle pane marked working after the background agent has completed.\n- Claude Code and Codex transcript or expanded-detail viewers no longer publish a false idle state while the pane is still showing active agent status.\n- Claude Code question prompts that use the arrow-glyph selector are now detected as blocked.\n- Kiro sub-agent tool approval prompts are now detected as blocked instead of working. (#388)\n- Shift-letter prefix bindings such as `prefix+shift+n` now work in legacy SSH terminal sessions that send uppercase letters without separate Shift metadata. (#312)\n- Idle panes now avoid repeated full foreground-process scans, reducing idle CPU on sessions with many panes. (#439)\n- Restored native agent sessions now resume across background workspaces and tabs after the first client provides terminal context instead of waiting until each pane is focused.\n- Pane input no longer waits behind the PTY actor's idle read poll, restoring responsive typing at quiet shell prompts. (#379)\n- Pane apps that query OSC 4 ANSI palette colors now receive the active terminal palette response, so OpenCode and similar TUIs can enable system-theme behavior inside Herdr. (#387)\n- Pane apps that query terminal capabilities with XTGETTCAP now receive supported capability responses, improving feature detection in Neovim and similar terminal apps. (#393)\n- Pane text selection now derives its highlight colors from the host terminal or active Herdr palette instead of forcing the theme's blue accent. (#298)\n- `herdr channel set preview` and `herdr channel set stable` now update direct installs from the selected channel immediately, reject preview on Homebrew and Nix installs before changing config, and show package-manager guidance for managed installs.\n- Plain `herdr update` and remote binary replacement now ask before stopping running sessions, avoid protocol-heavy prompt text, and leave the current install untouched when the user chooses not to stop active pane processes. Explicit `--handoff` update flows try live handoff without a second handoff prompt.\n- Remote bootstrap now uses the remote shell only for PATH discovery and runs internal probes through `/bin/sh`, so `herdr --remote` can detect existing installs when the remote login shell is fish. (#396)", - "protocol": 12, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.7/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.7/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.7/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.7/herdr-macos-aarch64" - } - }, - "0.6.6": { - "notes": "### Added\n- Custom command keybindings now accept an optional `description` field to provide user-defined descriptions shown in the keybind help panel instead of the default `'custom command'` label. (#362)\n\n### Fixed\n- The OpenCode integration no longer treats `session.created` or `session.updated` plugin events as idle signals, so active sessions stay marked working until OpenCode reports `session.status` or `session.idle`. (#351)\n- New interactive panes now use login-shell startup on macOS by default so Homebrew and other login PATH setup is available, with `terminal.shell_mode = \"non_login\"` as an opt-out. (#350)\n- Claude Code panes no longer stay blocked after stale permission-prompt reports when the visible screen has returned to idle or working state. (#349)\n- Codex panes no longer stay working because stale `esc to interrupt` text remains above a visible idle prompt, and visible approval-review work is now preserved as working. (#352)\n- Sidebar Git status refresh now deduplicates workspaces from the same checkout and reuses cached ahead/behind results when refs have not changed, reducing idle CPU from repeated `git` polling. (#353)\n- Update prompts, toasts, and docs now distinguish installing a new binary from stopping or reattaching a running Herdr session to use it.\n- Large restored sessions no longer leave restored or newly split panes without shells after startup, and live handoff keeps PTY ownership bounded to one master fd per pane. (#357)\n- Pane shutdown no longer warns that a pane is still alive after the direct child has already exited and been reaped. (#338)\n- Closing the last pane or tab in a parent worktree workspace now shows the existing confirmation before closing the whole worktree group. (#369)", - "protocol": 12, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.6/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.6/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.6/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.6/herdr-macos-aarch64" - } - }, - "0.6.5": { - "notes": "### Added\n- Added pane copy mode at `prefix+[` with keyboard navigation, visual selection, and clipboard yank support. (#231)\n- Added `foreground_cwd` to pane and agent API/CLI responses so integrations can inspect the active foreground process directory without changing the existing pane/workspace `cwd` semantics. (#345)\n- Added read-only `agent_session` metadata to pane and agent API/CLI responses when official integrations report native session references.\n\n### Fixed\n- Live handoff now preserves terminal state when transferring supported running panes to a replacement server.\n- WSL clipboard writes now prefer OSC 52 before WSLg clipboard tools, so mouse selection and double-click copy populate Windows clipboard history in Windows Terminal. (#333)\n- Incomplete host terminal OSC default-color replies no longer get misread as Alt-key input and forwarded into panes, preventing interactive prompts such as `gh auth login --web` from aborting on split `ESC ]` input. (#279, #306, #344)\n- Workspace rename prompts and background notifications now use live cwd-derived workspace labels instead of stale session labels. (#332)\n- `herdr session stop` no longer fails on zero-duration socket timeouts when the stop deadline is nearly exhausted.\n- Update preview instructions now wrap long package-manager commands instead of truncating the shell command suffix.\n- Restored native agent resume panes now fall back to a shell when the resumed agent exits instead of closing the whole pane.", - "protocol": 11, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.5/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.5/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.5/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.5/herdr-macos-aarch64" - } - }, - "0.6.4": { - "notes": "### Fixed\n- Fixed macOS server startup with large restored sessions by raising the server file descriptor soft limit, preventing new panes from failing with `dup of fd N failed` or `Too many open files` around 40 live panes. (#327)\n\nThis is a hotfix for v0.6.3. See the v0.6.3 notes for the full feature release.", - "protocol": 11, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.4/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.4/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.4/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.4/herdr-macos-aarch64" - } - }, - "0.6.3": { - "notes": "### Added\n- Added native agent session restore behind `[session] resume_agents_on_restore`, allowing supported Pi, Claude Code, Codex, OpenCode, and Hermes panes with current official integrations to restart into their previous agent conversation after a Herdr server restart. (#233)\n- Added opt-in pane screen history across full server restarts with `[experimental] pane_history = true` and Settings > Experiments > pane screen history. (#217, #248, thanks @icedac)\n- Added a session navigator at `prefix+g` with a searchable workspace/tab/pane tree, agent state filters, mouse switching, and keyboard navigation. (#157)\n- Added configurable navigate-mode movement bindings for workspace and pane navigation keys. (#193)\n- Added a configurable `last_pane` keybinding action for tmux-style back-and-forth navigation to the last focused pane across workspaces and tabs. It is unset by default. (#287)\n- Added scrollback support to direct agent terminal attaches. Mouse wheel and plain PageUp/PageDown now scroll the attached terminal viewport, while terminal apps that request mouse or alternate-scroll input still receive those events. The client/server protocol is now version 11.\n- Added `ui.redraw_on_focus_gained` to keep the existing full redraw on outer-terminal focus gain by default while allowing users to opt out of the visible refresh. (#282)\n- Added `ui.mobile_width_threshold` to configure the terminal width at which Herdr switches to the mobile single-column layout. (#317)\n- Added `--handoff` for `herdr update` and `herdr --remote` to opt into live server handoff for supported running servers. Plain update and remote attach use the normal restart/stop flow by default.\n- Added `pane.report_metadata` and `herdr pane report-metadata` so user hooks can customize pane titles, displayed agent names, compact status labels, and visible state labels without taking over integration-owned lifecycle or session state. (#36)\n- Added tmux-style double-click token copy in panes, with temporary copy feedback and mouse passthrough preserved for terminal apps that request mouse input. (#142, #296, thanks @babymastodon)\n- Added Ctrl-click URL opening inside panes for OSC 8 hyperlinks and visible `http://` or `https://` URLs when the host terminal sends the modified click to Herdr. (#307)\n- Added Qoder CLI detection, terminal state heuristics, and `herdr integration install qodercli` hook support. (#308, #309, thanks @wayneleelwc)\n\n### Fixed\n- Remote bootstrap now downloads exact-version release assets for Homebrew and Nix clients instead of copying package-manager-managed local binaries into `~/.local/bin/herdr`.\n- `website/latest.json` now stores asset URLs for archived releases under `releases[version].assets`, so remote bootstrap can fetch the current client version even when Homebrew and the top-level latest release are temporarily out of sync.\n- App and server event queues no longer stall under load, improving delivery of pane and agent state updates. (#265)\n- Agent status subscriptions now deliver already-matching states and event-hub notifications reliably for waits and automation. (#288, #295)\n- Codex background terminal waits are detected more reliably, and idle agent checking uses less CPU. (#300)\n- Split OSC 10/11 host color replies are buffered correctly, so terminal apps still receive host foreground/background color responses when replies arrive in chunks. (#306, #310)\n- `herdr session stop` is more reliable when the server closes the socket early or stops without sending a full response.\n- The OpenCode integration now releases pane ownership on plugin dispose, preventing stale integration state after OpenCode exits. (#314)\n- Linux sound alerts no longer fall back to `aplay` for mp3 files, preventing static noise on systems without `paplay`. Herdr now tries mp3-capable players such as `pw-play`, `ffplay`, `mpg123`, and `mpv` instead. (#290)", - "protocol": 11, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.3/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.3/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.3/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.3/herdr-macos-aarch64" - } - }, - "0.6.2": { - "notes": "### Added\n- Added optional Nix flake support for building, running, installing, and developing Herdr with Nix. (#208, #221, #264)\n- Added `terminal.new_cwd` to choose whether new panes, tabs, and workspaces follow the source pane/workspace, start in `$HOME`, use Herdr's process directory, or use a fixed path.\n- Added `herdr integration install omp` for OMP's `.omp` extension directory. The extension reports OMP pane state through Herdr's socket API without relying on native `omp` process detection.\n- Added CLI and socket API support for Git worktrees with `herdr worktree list/create/open/remove`, optional worktree provenance on workspace responses, and client/server protocol version 10.\n\n### Fixed\n- GitHub Copilot CLI sessions now use tested terminal heuristics for approval prompts, freeform input, plan review, and thinking states in the Agents panel. (#232, #256, thanks @LaneBirmingham)\n- Kiro approval prompts are now detected as blocked in the Agents panel. (#255)\n- Workspace labels now follow the live pane working directory after directory changes.\n- Remote clients using local keybindings no longer show stale server keybinding warnings from the remote host.", - "protocol": 10, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.2/herdr-macos-aarch64" - } - }, - "0.6.1": { - "notes": "### Added\n- Added `ui.mouse_scroll_lines` to configure how many pane scrollback lines each mouse wheel notch scrolls. The default remains 3. (#236)\n- Added `--remote-keybindings local|server` for `herdr --remote`. Remote attach now uses the launching client's local keybindings by default without copying config files to the remote host; use `--remote-keybindings server` to keep the remote server's keybindings. The client/server protocol is now version 9.\n- Added `experimental.reveal_hidden_cursor_for_cjk_ime = false` (opt-in), `experimental.cjk_ime_agents = []` (optional allow-list), and `experimental.cjk_ime_cursor_shape = \"steady_block\"` to expose the focused pane's cursor anchor to the outer terminal even when the pane requested `?25l`, restoring macOS IME candidate-window tracking for TUIs that paint their own cursor (Claude Code, pi, codex). When `cjk_ime_agents` is non-empty, the reveal applies only to focused panes whose detected agent matches one of the listed names. When the pane reports no cursor position, the anchor falls back to the pane's top-left so a stable IME hint is always available. Trade-off when enabled: an extra hardware cursor may appear in the outer terminal for apps that hide the cursor without painting a replacement. (#149, thanks @ChihGodlee)\n- Added explicit sidebar Git worktree groups plus native worktree creation, existing checkout open, and safe checkout cleanup flows, configured by `[worktrees].directory`, `keys.new_worktree`, optional `keys.open_worktree`, and optional `keys.remove_worktree`. (#137)\n- Added named-session reattach and stop command hints so detach and update guidance point back to the active session. (#199, thanks @Golden-Pigeon)\n\n### Fixed\n- Pane apps that query OSC 10/11 default foreground/background colors now receive the host terminal colors, so OpenCode and similar TUIs can detect light terminal themes inside Herdr. (#253)\n- Codex Plan mode question prompts now override stale integration `working` reports when the visible terminal UI is clearly waiting for an answer, stale hook authority is cleared when foreground process detection sees Codex exit back to the shell, and Claude Code cancellations now recover from stale hook `working` reports when the idle prompt returns. (#249)\n- Keybinding parsing now accepts non-ASCII printable keys such as `\u00f6`, `\u00e9`, and `\u011f`, including UTF-8 Alt chords. (#247)\n- Kimi Code CLI sessions now use structural terminal detection for approval prompts and live thinking/tool status, improving working and blocked state reporting in the Agents panel. (#215)\n- Antigravity CLI (`agy`) sessions are now detected, and their terminal UI now reports working and blocked states in the Agents panel. (#207)\n- Cursor Agent sessions launched as `cursor-agent` or symlink aliases such as `agent` are now detected, and their terminal UI now reports working and blocked states in the Agents panel. (#225)\n- Agent detection now ignores runtime argument strings when identifying foreground processes, reducing false positives from helper commands and wrapped processes. (#238)\n- In-app notifications now stay below interactive floating overlays, so dialogs and menus remain readable and clickable while a toast is visible. (#228)\n- `herdr --remote` now offers to restart the remote server after installing or replacing a remote binary, or when the running server version differs, even if the client/server protocol is still compatible.", - "protocol": 9, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.1/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.1/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.1/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.1/herdr-macos-aarch64" - } - }, - "0.6.0": { - "notes": "### Added\n- Added keybinding v2 with explicit `prefix+...` syntax, array bindings per action, configurable prefix-mode pane focus, tab switching, and direct modified chords for users who opt in. (#154, #201, #202, #219)\n- Added `herdr config reset-keys` to back up `config.toml` and remove custom keybindings so built-in v2 defaults apply on restart or config reload. (#154)\n- Added an integrations tab in settings and first-run onboarding so users can install recommended agent integrations from inside Herdr.\n- Added update badges on the sidebar menu, settings menu item, and integrations settings tab when installed integrations are outdated.\n- Added `terminal.default_shell` to choose the executable used for new interactive panes. When unset, Herdr still falls back to `$SHELL`, then `/bin/sh`. (#196)\n- Added native Kiro CLI detection with idle and working state heuristics. (#185)\n\n### Fixed\n- Keybinding conflict warnings now stay visible and show one readable yellow row per conflicting binding.\n- Update prompts that need to stop a running server now default Enter to yes and show `[Y/n]`.\n- Pending release notes no longer open automatically on startup; the latest notes remain available from the menu.\n- Running `herdr server` directly now prints socket and log paths and explains that normal TUI users should run `herdr`.\n- Kitty graphics virtual Unicode placeholders now render image placements instead of leaving placeholder cells behind. (#136)\n- Clipboard image reads are now capped to Herdr's image payload limit, preventing oversized local clipboard images from being read into memory.\n- The install script now reads Herdr's public latest-release manifest, so fresh installs use the same binary URLs as `herdr update`.\n- The Claude Code integration no longer lets subagent completion hooks report durable `working`, preventing delayed recap or subagent completion events from reviving an idle pane. (#198)\n- Remote clients now bridge local clipboard images into the remote pane by staging them as temporary image files and pasting the remote path, so Claude Code image paste works over `herdr --remote`. (#205)\n\n### Breaking Changes\n- Removed the separate `keys.quit` binding. Use `keys.detach`, which detaches in server mode and exits in `--no-session` mode. The default detach binding is now `prefix+q`.\n- Keybindings now use explicit trigger syntax: `prefix+c` means prefix mode, while `ctrl+alt+c` is direct. Bare printable direct bindings such as `new_tab = \"c\"` are rejected with diagnostics because they intercept normal typing. The default keymap now gives tmux-style tab actions to `prefix+c`, `prefix+n`/`prefix+p`, and `prefix+1..9`, uses `prefix+w` for workspace navigation, and moves pane focus to `prefix+h/j/k/l`. (#154)\n- The client/server protocol is now version 8. Stop and restart any running v0.5.12 server before attaching with this release.", - "protocol": 8, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.6.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.6.0/herdr-macos-aarch64" - }, - "announcement": { - "id": "keybinding-v2", - "title": "Keybind Refactor", - "body": "### Breaking change: keybinding syntax changed\n\nHerdr now uses explicit tmux-style keybindings. If you want the new defaults, run `herdr config reset-keys`. Herdr backs up your config first, removes only keybinding settings, and preserves non-key settings.\n\nBefore, many keybinding values implicitly meant \"after pressing the prefix\". Now the binding must say that directly:\n\n- Before: `new_tab = \"c\"`\n- After: `new_tab = \"prefix+c\"`\n\nBindings without `prefix+` are direct terminal-mode shortcuts. Direct shortcuts can intercept keys before shells, editors, tmux, SSH, and terminal apps receive them. If your current config has old bare keybindings, Herdr may warn about them or disable unsafe bindings.\n\nThe new defaults are prefix-first:\n\n- `prefix+c` creates a tab\n- `prefix+n` / `prefix+p` switch tabs\n- `prefix+1..9` switches tabs\n- `prefix+h/j/k/l` focuses panes\n- `prefix+w` opens workspace navigation\n\nPlease read the updated keybinding docs before customizing again:\n\nhttps://herdr.dev/docs/configuration/" - } - }, - "0.5.12": { - "notes": "### Fixed\n- The Claude Code integration no longer reports successful or failed post-tool hooks as `working`, and installing the updated integration removes Herdr's deprecated post-tool hook entries from existing Claude settings. (#198)\n- The Codex integration now reports native `PermissionRequest` hooks as `blocked`, so permission prompts no longer stay pinned as `working` after a tool-use hook. (#198)\n- Workspace and tab rename prompts now handle Backspace, Ctrl+Backspace, Alt+Backspace, Cmd+Backspace, Ctrl+H, Ctrl+W, and Ctrl+U as editing shortcuts instead of inserting stray characters or clearing unexpectedly. (#204)", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.12/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.12/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.12/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.12/herdr-macos-aarch64" - } - }, - "0.5.11": { - "notes": "### Added\n- Added the `terminal` built-in theme, which uses the host terminal's ANSI palette for Herdr UI colors. (#140, #146, thanks @babymastodon)\n- Added Hermes Agent foreground-process detection with basic idle, working, and blocked heuristics. (#144)\n- Added a Hermes Agent plugin integration for direct state reporting. (#144)\n- Added `ui.sidebar_min_width` and `ui.sidebar_max_width` to configure the sidebar's expanded resize bounds. Defaults remain 18 and 36 columns; existing configs are unchanged. (#132, #135, thanks @ChihGodlee)\n\n### Fixed\n- Running the internal `herdr client` command from inside Herdr now respects the nested-launch guard, and the command is no longer advertised in root help. (#187)\n- The Herdr agent skill now refuses to claim pane ownership unless it is running inside Herdr. (#152)\n- Terminal-style docs code blocks now keep their copy button in the top-right corner. (#190)\n- The sidebar `new` workspace button now aligns with the sidebar's left padding. (#189)\n- Herdr now preserves `session.json` symlinks when saving persistent session state. (#139, #147, thanks @cloudmanic)\n- Alt+Backspace is now preserved when forwarded into panes. (#155, #165)\n- Directional pane focus now works while a tab is zoomed. (#151, #167)\n- Agent detection now prefers the foreground process group leader, reducing false matches from child helper processes. (#161, #172)\n- Remote attach now uses a matching `herdr` already available on the remote `PATH` before installing a new copy. (#170)\n- Modified Enter input such as Shift+Enter is now preserved in supported terminals. (#168)\n- Sidebar agent entries now show user-assigned agent names when available. (#145)\n\n### Breaking Changes\n- The client/server protocol is now version 7. Stop and restart any running v0.5.10 server before attaching with this release.", - "protocol": 7, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.11/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.11/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.11/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.11/herdr-macos-aarch64" - } - }, - "0.5.10": { - "notes": "### Added\n- Added indexed keybind families under `[keys.indexed]` for jumping directly to workspace, tab, or visible agent positions 1-9.\n- Added hook-owned custom agent status labels, so integrations can show short visual states like `indexing` without changing semantic agent status.\n- Added terminal-backed agent commands and socket API methods for listing, reading, sending to, renaming, focusing, waiting on, attaching to, and starting agent terminals.\n- Added direct terminal attach with `herdr agent attach <target>` and `herdr terminal attach <terminal_id>`.\n- Added `ui.prompt_new_tab_name = false` for creating new tabs immediately with generated names instead of opening the rename dialog. (#123)\n- Added optional `keys.edit_scrollback` to open the focused pane's retained scrollback in `$EDITOR` inside a temporary zoomed pane. (#122)\n\n### Changed\n- Renamed the focused pane fullscreen keybinding to `keys.zoom`; `keys.fullscreen` remains supported as a legacy alias.\n\n### Fixed\n- Grok Build is now detected as `grok`, with basic working, blocked, and idle state detection. Conflicting known-agent hook labels are ignored once native foreground-process detection identifies a different known agent. (#133)\n- Terminal cursor shapes now forward through attached clients. (#116)\n- Herdr now redraws immediately when the outer terminal regains focus.\n- GitHub Copilot is now correctly detected when its process name is `copilot`. (#118)\n- Integration installs now respect `PI_CODING_AGENT_DIR`, `CLAUDE_CONFIG_DIR`, and `CODEX_HOME` when choosing Pi, Claude Code, and Codex config paths. (#121)\n- Split pane resize hit areas no longer overlap the first content column or row, making text selection work from the start of right and bottom panes. (#120)\n- Dragging text selections near pane edges now autoscrolls into scrollback, and selection state now clears correctly when switching workspaces, tabs, or panes. (#128, #129, thanks @leeeanh)\n- Zoomed panes now keep their border visible in tabs that contain multiple panes. (#115)", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.10/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.10/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.10/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.10/herdr-macos-aarch64" - } - }, - "0.5.9": { - "notes": "### Added\n- Added experimental Kitty graphics rendering for local panes and attached clients behind `experimental.kitty_graphics`, including support for larger graphics frames.\n- Added `ui.toast.delivery = \"system\"` for OS-level background notifications, using `notify-send` on Linux and `terminal-notifier` or `osascript` on macOS.\n- Added light variants for Catppuccin, Tokyo Night, Gruvbox, One, Solarized, Kanagawa, and Ros\u00e9 Pine themes.\n- Added `ui.mouse_capture = false` for tmux-style mouse behavior, letting the terminal handle normal clicks while still forwarding mouse input to pane apps that request it.\n\n### Changed\n- Moved experimental settings into `[experimental]`.\n\n### Fixed\n- PageUp and PageDown now scroll Herdr pane scrollback for normal panes while still forwarding keys to full-screen or mouse-reporting apps.\n- Enhanced tilde key sequences now parse correctly, improving compatibility with terminals that emit them.\n- `herdr integration install codex` now enables the current Codex `[features] hooks = true` flag and migrates the deprecated top-level `codex_hooks` flag.\n\n### Breaking Changes\n- `advanced.allow_nested` has moved to `experimental.allow_nested`; update configs that allow nested Herdr launches.\n- The client/server protocol is now version 5. Stop and restart any running v0.5.8 server before attaching with this release.", - "protocol": 5, - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.9/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.9/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.9/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.9/herdr-macos-aarch64" - } - }, - "0.5.8": { - "notes": "### Added\n- Added manual pane labels through `herdr pane rename`, the `pane.rename` socket API, an optional `keys.rename_pane` binding, and the right-click pane menu.\n- Added `ui.show_agent_labels_on_pane_borders`, which can show detected or reported agent names in split pane borders when no manual pane label is set.\n- Added `herdr integration status [--outdated-only]` so installed agent integrations can be checked for legacy or outdated versions.\n- Added an optional `keys.open_notification_target` binding for jumping to the pane behind the current notification.\n- Added optional `keys.previous_agent` and `keys.next_agent` bindings for cycling through sidebar agent entries.\n\n### Changed\n- Scrolling over the tab bar now switches tabs directly, including overflowing tab bars.\n\n### Fixed\n- Indexed terminal palette colors now render correctly for 256-color terminal apps.\n- Hook-based agent integrations now reject stale out-of-order reports and base notifications on effective agent state, reducing duplicate or stuck state changes.\n- Background tabs now resize when the outer terminal size changes, preventing stale pane dimensions when switching back to them.\n- Client shutdown now drains queued control messages more reliably.\n- Pane cursors are now hidden while scrolled back, and omitted while the mobile switcher is open.\n- Mobile agent switcher entries now include tab context, making agents easier to identify on narrow terminals.\n- macOS foreground job detection now uses process groups, improving agent state tracking for foreground commands.\n- Remote SSH no longer fails before connecting when macOS temporary bridge socket paths exceed Unix socket length limits. (#103, thanks @moonsphere)\n- Nix-wrapped agent commands are now detected by their underlying agent entrypoint.\n- Pane renames made through the socket API now rerender immediately.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.8/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.8/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.8/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.8/herdr-macos-aarch64" - } - }, - "0.5.7": { - "notes": "### Added\n- Added ANSI-formatted pane reads to the CLI and socket API with `herdr pane read --format ansi` / `--ansi`, preserving colors and styles for visible and recent pane output.\n\n### Changed\n- The agents panel now highlights the currently focused agent entry, matching the active workspace styling. (#84, thanks @soomtong)\n\n### Fixed\n- Git branch and ahead/behind refreshes now run off the main loop, preventing slow Git status checks from freezing the UI.\n- Update and startup flows now detect incompatible running servers earlier and give clear stop/restart guidance instead of trying to attach with a mismatched client/server protocol.\n- `herdr update` now downloads and prepares the new binary before stopping a running server, reducing the chance of interrupting an active session when download or install preparation fails.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.7/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.7/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.7/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.7/herdr-macos-aarch64" - } - }, - "0.5.6": { - "notes": "### Added\n- Added the `vesper` built-in theme. (#71, thanks @nexxeln)\n- Added `herdr --remote <ssh-target>`, so you can use Herdr as a thin client for remote servers without SSHing in first. Herdr connects over SSH, bootstraps a matching remote `herdr` binary when needed, starts the remote server automatically, and streams an efficient terminal view back to your local terminal.\n\n### Changed\n- Updated the bundled `libghostty-vt` engine and removed the custom Linux C++ runtime link workaround from static builds.\n- CLI workspace, tab, and pane creation now preserve the current focus by default; pass `--focus` to switch to the newly created item.\n\n### Fixed\n- OSC 8 hyperlinks emitted inside panes now remain clickable after Herdr renders them, including titled markdown-style links.\n- Agent panel scope now defaults to `all` and is saved to config when changed, so choosing `current` or `all` survives session resets and upgrades.\n- Native agent hook state now clears when the detected native agent exits, preventing stale hook-reported status from sticking to a pane.\n- Clicking an in-app agent toast now jumps to the relevant pane and clears the toast after focus.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.6/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.6/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.6/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.6/herdr-macos-aarch64" - } - }, - "0.5.5": { - "notes": "### Added\n- Added a mobile layout for narrow terminals, making it practical to SSH into your machine and run herdr from your phone.\n\n### Fixed\n- Non-ASCII terminal input is no longer dropped when UTF-8 characters arrive split across multiple reads.\n- Native agent detection now clears agents after their foreground process exits and control returns to the shell, preventing stale agent status in the sidebar.\n- Pane contents no longer shift horizontally when scrollback appears, keeping the scrollbar gutter stable.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.5/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.5/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.5/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.5/herdr-macos-aarch64" - } - }, - "0.5.4": { - "notes": "### Fixed\n- Visible active-tab panes that finish while the outer terminal is unfocused are now marked as seen when you return to herdr, preventing stale done/attention indicators.\n- IME candidate windows and mobile SSH cursor tracking now stay anchored to the focused pane during client redraws, including apps that hide the cursor, instead of drifting to sidebar or repaint positions.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.4/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.4/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.4/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.4/herdr-macos-aarch64" - } - }, - "0.5.3": { - "notes": "### Added\n- Added named persistent sessions, so you can keep separate herdr environments for different projects or contexts while sharing the same global config. See the docs for the full session CLI. (#57, thanks @fbettag)\n- Added `herdr status`, `herdr status server`, and `herdr status client` to inspect the local client, running server, protocol compatibility, socket path, and whether a restart is needed.\n\n### Changed\n- Focused panes can now still alert you through terminal notifications when the herdr terminal window is unfocused, so active work does not go quiet just because you switched to another app.\n\n### Fixed\n- Dragging pane split borders now works when the app inside the pane has mouse reporting enabled, including Claude Code no-flicker mode. (#61, thanks @EYH0602)\n- Pressing the prefix key twice now forwards a literal prefix key into the focused pane in client mode again.\n- `herdr integration install` and `herdr integration uninstall` now work without requiring a running herdr server.\n- Pane PTYs now keep their last attached size while detached, preventing detached output from being resized or rewrapped to fallback dimensions.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.3/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.3/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.3/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.3/herdr-macos-aarch64" - } - }, - "0.5.2": { - "notes": "### Added\n- Config can now be reloaded in the running app/server from the global menu or with `herdr server reload-config`, applying safe live settings without restarting the persistent server.\n\n### Fixed\n- Persistent server startup now surfaces config diagnostics in attached clients instead of silently hiding parse or validation errors.\n- Pane backgrounds now stay transparent when the host terminal background color is unknown, while explicit terminal cell backgrounds still render correctly.\n- Persistent-session toast and sound notifications now target the foreground attached client instead of firing across every connected client.\n- Claude Code subagent hook events no longer make the parent Claude pane look idle or released when a subagent finishes, and permissioned tool-call completion keeps the pane in the correct working state.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.2/herdr-macos-aarch64" - } - }, - "0.5.1": { - "notes": "### Added\n- Toast notifications can now be delivered through the outer terminal as desktop notifications. Configure this with `ui.toast.delivery = \"terminal\"`; see the [configuration docs](https://herdr.dev/docs/configuration/) for details.\n- Herdr now writes separate capped support logs for app, client, and server modes, making persistent-session issue reports easier to diagnose without unbounded log growth.\n- The bundled opencode plugin now reports question prompts as blocked while waiting for user input, then returns to working or idle when answered or dismissed. Question prompts are also detected by the default terminal-screen heuristics. (#51, thanks @mspiegel31)\n\n### Changed\n- Routine API request traces now log at debug level by default, making normal support logs smaller and easier to read while preserving detailed traces when debug logging is enabled.\n\n### Fixed\n- Pasted text and other reverse-video terminal content now stays readable when pane backgrounds are transparent. (#45, thanks @EYH0602)\n- Panes now advertise a stable `TERM=xterm-256color` and `COLORTERM=truecolor` by default, improving redraw and cursor behavior in shells and remote sessions.\n- Pane scrollbars once again reserve their own rightmost column instead of overlaying terminal content in persistent session mode.\n- Terminal-delivered toast notifications now use the server-approved delivery decision in persistent session mode, so attaching clients do not incorrectly suppress them.\n- In-app toast delivery now stays inside herdr instead of also forwarding a terminal/desktop notification.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.1/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.1/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.1/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.1/herdr-macos-aarch64" - } - }, - "0.5.0": { - "notes": "### Breaking Changes Please Read\n- herdr now defaults to a persistent server/client session model. running `herdr` starts or reattaches to a background session server instead of launching the old single-process UI.\n- quitting the UI in default mode now detaches the current client and leaves the shared session running. use `herdr server stop` to stop the background server explicitly.\n- the old monolithic behavior is still available as an escape hatch with `herdr --no-session`.\n\n### Added\n- Persistent sessions are now the default product behavior. You can detach and reattach without stopping pane processes.\n- Added the thin client and headless server as first-class product components, including auto-detect launch, explicit `herdr client`, and `herdr server stop`.\n- Sessions now restore cleanly after full restart, preserving workspaces, tabs, panes, and running process state.\n- Multi-client attach is now supported. Multiple clients can connect to the same shared session.\n\n### Changed\n- In persistence mode, in-app quit actions now detach the current client by default instead of shutting down the whole background server.\n- The current persistence model is a shared session view across attached clients. It is not yet full tmux-style per-client independent navigation.\n- Restored sessions now land in terminal mode, while fresh sessions still start in navigate mode.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.5.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.5.0/herdr-macos-aarch64" - } - }, - "0.4.11": { - "notes": "### Breaking Changes Please Read\n- The update flow changes in `0.4.11`. Herdr no longer installs updates silently in the background. Starting with this release, herdr only checks for updates and shows them in the UI. To install a new release, quit herdr and then run `herdr update` manually in your shell.\n- This prepares the upcoming `0.5.0` persistence release. Herdr is moving from the old single-binary update model toward a persistent server/client session model, so your workspace can keep running while clients attach, detach, and reconnect.\n- The reason for this change is upgrade safety. Herdr needs to stop the old running process cleanly before the new client/server model takes over, so manual update avoids mixed-version states during the transition.\n\n### Added\n- Hook-reported agent state can now use custom agent labels, so integrations are no longer limited to herdr\u2019s built-in agent names. Custom labels now flow through pane/workspace UI and the socket API anywhere agent names are shown.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.11/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.11/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.11/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.11/herdr-macos-aarch64" - } - }, - "0.4.10": { - "notes": "### Added\n- Prefix mode now supports custom command keybindings via `[[keys.command]]`, so you can launch detached shell helpers or open temporary overlay panes from inside herdr using the active workspace, tab, pane, and cwd context.\n- Pressing the prefix key twice now forwards a literal prefix keystroke into the focused pane, which makes nested tools and terminal apps that use the same prefix easier to control.\n\n### Fixed\n- App-level key handling now normalizes enhanced keyboard reporting consistently, so shifted bindings and text like `?` and uppercase characters work correctly in navigate mode and text-entry UI.\n- Ctrl+letter input is now encoded correctly when pane apps enable kitty keyboard mode, improving compatibility with terminal programs that expect CSI-u style key reporting.\n- The collapsed sidebar now keeps the active workspace visibly highlighted even while you stay in terminal mode.\n- Droid Mission Control screens are now treated as idle instead of active work, reducing false busy-state detection.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.10/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.10/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.10/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.10/herdr-macos-aarch64" - } - }, - "0.4.9": { - "notes": "### Fixed\n- Droid's primary-screen redraws no longer erase pane scrollback inside herdr, while normal scrollback-clear behavior is preserved elsewhere.\n- `q` is now dedicated to quitting in navigate mode instead of also acting as a generic cancel key in modals and overlays, reducing accidental quits.\n- Tab bar scrolling is tighter: the scroll-right button and new-tab button now sit directly adjacent to the last visible tab without a gap, and manual scroll no longer overscrolls past the last tab.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.9/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.9/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.9/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.9/herdr-macos-aarch64" - } - }, - "0.4.8": { - "notes": "### Added\n- Themes can now set `panel_bg = \"reset\"` to let herdr\u2019s panel chrome inherit the host terminal background instead of painting an opaque panel fill. This also accepts the aliases `default`, `none`, and `transparent`.\n- Ghostty-backed panes now preserve the host terminal\u2019s default background when it matches the outer terminal theme, so terminal window transparency can show through pane content instead of being repainted as an opaque color.\n\n### Fixed\n- Clipboard writes now prefer native platform clipboard tools (`pbcopy`, `wl-copy`, `xclip`, or `xsel`) before falling back to OSC 52, which makes copy operations from panes more reliable across terminal setups.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.8/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.8/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.8/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.8/herdr-macos-aarch64" - } - }, - "0.4.7": { - "notes": "### Added\n- The tab bar now handles large tab sets better: you can scroll overflowing tabs with the mouse controls or wheel, and reorder tabs by dragging them.\n- `workspace create` and `tab create` now return the created root pane in their JSON response, so automation can act on the new pane immediately without an extra lookup.\n\n### Fixed\n- Background panes that start idle no longer show up as `done` or trigger finished-state attention until they have actually transitioned from working or blocked to idle.\n- Left-click now focuses panes and right-click now opens the pane context menu even when the inner TUI has mouse reporting enabled, fixing apps like Claude Code. (#25, thanks @othavioquiliao)\n- OSC 52 clipboard writes from apps running inside panes now reach the host clipboard correctly, including copy requests emitted by child processes inside the pane.\n- `pane close` now removes only the targeted tab when other tabs still exist in the workspace, instead of closing the whole workspace.\n- Amp approval prompts are now detected more reliably as blocked, including tool-call, command, and file edit/create approval screens.\n\n### Breaking Changes\n- Socket API clients that match `result.type` exactly need to handle `workspace_created` and `tab_created` for `workspace.create` and `tab.create`; these calls no longer return `workspace_info` and `tab_info`.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.7/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.7/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.7/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.7/herdr-macos-aarch64" - } - }, - "0.4.6": { - "notes": "### Fixed\n- Agent state detection is now more reliable when panes are scrolled back, when Codex is running in narrow panes, and when Claude opens slash-command or settings menus, reducing false blocked or idle states.\n- Mouse-driven terminal text selection now autoscrolls into pane scrollback and clears cleanly after copy, so selecting beyond the visible viewport works as expected.\n- Pane terminal colors now return to the outer terminal theme after fullscreen TUIs exit, fixing cases like Droid leaving stale background colors behind. This restore path now also works correctly on macOS.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.6/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.6/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.6/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.6/herdr-macos-aarch64" - } - }, - "0.4.5": { - "notes": "### Added\n- `herdr workspace create` and `herdr tab create` now support `--label`, so scripts and agents can name new workspaces and tabs immediately instead of creating them first and renaming them afterward.\n- The global menu now includes a manual **reload keybinds** action, so you can apply `config.toml` keybinding changes without restarting herdr.\n- The socket API and CLI now expose a `done` agent status, including `herdr wait agent-status --status done`, so automation can distinguish finished agent runs from panes that are merely idle.\n\n### Changed\n- Session state is now saved automatically with a debounce while you work, so recent workspace, tab, pane, and sidebar changes are preserved more reliably even if herdr exits unexpectedly.\n\n### Fixed\n- Only the focused pane now owns the terminal cursor, which removes stray cursor blocks from unfocused panes.\n- In-app **What's New** / release notes now render inline code spans and fenced code blocks correctly.\n- Default numbered tabs now stay auto-named when you keep or rename them back to their numeric label, so generated tab numbering stays compact and predictable.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.5/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.5/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.5/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.5/herdr-macos-aarch64" - } - }, - "0.4.4": { - "notes": "### Changed\n- The expanded sidebar can now be split into resizable workspace and agent sections with a draggable divider, and that section sizing is preserved across restarts.\n\n### Fixed\n- IME input now works properly for Chinese and other UTF-8 input methods in pane terminals, so candidate selection no longer falls back to typing raw digit keys. (#9, thanks @Edmund-a7)\n- `herdr pane run ...` now uses the bracketed-paste-aware input path, improving compatibility with shells and terminal apps that expect pasted command text to arrive atomically.\n- The local socket API is more robust and secure: its Unix socket is now restricted to the current user, and long-running output waits and subscriptions stop cleanly on disconnect or shutdown instead of hanging indefinitely.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.4/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.4/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.4/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.4/herdr-macos-aarch64" - } - }, - "0.4.3": { - "notes": "### Fixed\n- Update checks and in-app **What's New** release notes no longer depend on GitHub\u2019s release API, which avoids the transient 403 failures from the previous update path.\n- `herdr pane run ...` now submits the full command atomically in one request, fixing cases where scripted commands did not reliably execute because the final Enter was sent separately.\n- Bare line-feed input is now preserved in raw terminal input instead of being normalized to Enter, fixing Linux terminal cases where inputs like Shift+Enter or Ctrl+J could be interpreted incorrectly.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.3/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.3/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.3/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.3/herdr-macos-aarch64" - } - }, - "0.4.2": { - "notes": "### Added\n- The expanded sidebar agent panel can now switch between the current workspace and all workspaces, so you can scan and jump to agents across the whole session.\n- The collapsed sidebar now shows compact per-pane agent indicators, so you can keep an eye on agent activity without reopening the full sidebar.\n\n### Changed\n- The sidebar now handles larger workspace sets more cleanly: the workspace section has headers, its own scrolling, better-aligned drag/drop slots, and manual width changes persist across restarts. Double-clicking the divider resets it to the configured default width.\n- Pane scrollback is now configured with `advanced.scrollback_limit_bytes`, matching Ghostty's byte-based scrollback limit. Set it to `0` to disable pane scrollback entirely. The old `advanced.scrollback_lines` key is still accepted as an alias, but it now uses the same byte-based value.\n- Linux release binaries now ship with libghostty SIMD enabled again without reintroducing the musl startup issue, restoring the optimized Linux build path.\n\n### Fixed\n- Typing in pane terminals on macOS is responsive again after the Ghostty migration, by keeping a persistent per-pane Ghostty key encoder instead of rebuilding it on every keypress.\n- The collapsed sidebar expand toggle works again.\n- Creating a new tab now waits until you confirm the dialog, so cancelling the new-tab flow no longer leaves behind an unwanted tab.\n- Copying selected pane text now uses Ghostty's native selection extraction, which preserves wrapped text and wide characters more accurately.\n- Session restore is more tolerant of older and current snapshot formats, including pre-tab session files.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.2/herdr-macos-aarch64" - } - }, - "0.4.1": { - "notes": "### Fixed\n- Fixed Linux release binaries crashing on startup.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.1/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.1/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.1/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.1/herdr-macos-aarch64" - } - }, - "0.4.0": { - "notes": "### Major Changes\n- Herdr now uses a Ghostty-backed terminal engine as its pane runtime.\n- The legacy vt100 pane backend has been removed, making Ghostty the single terminal backend going forward.\n\n### UX and Interaction\n- Workspaces can now be reordered by dragging them in the sidebar.\n- Notification sounds now support custom mp3 file overrides, with either one shared file or separate files for finished vs needs-attention alerts.\n\n### API and Integration\n- Workspace API ids are now stable, making socket and CLI automation more predictable across workspace changes and restores.\n\n### Packaging and Runtime\n- macOS builds now statically link the vendored `libghostty-vt`, preserving the single-binary install and update flow.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.4.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.4.0/herdr-macos-aarch64" - } - }, - "0.3.2": { - "notes": "### Changed\n- The global launcher now surfaces update-related actions more clearly: when release notes are available you can open **What's New**, and when an update has been downloaded you can **quit to apply update** directly from the menu.\n- Release notes are now retained as the latest available notes after you dismiss the startup modal, so you can reopen them later from the UI instead of only seeing them once.\n\n### Fixed\n- Fixed held-key repeat in terminal panes on macOS terminals that send explicit repeat events through the enhanced keyboard protocol, restoring continuous backspace, character, and arrow-key repeat without letting modal close/confirm key repeats leak into the shell.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.3.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.3.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.3.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.3.2/herdr-macos-aarch64" - } - }, - "0.3.1": { - "notes": "### Added\n- New tabs now open directly into the rename flow, with the default tab name prefilled and replaced on first type so you can name tabs as you create them.\n\n### Changed\n- Polished modal layout and spacing across onboarding, settings, keybind help, and release notes so overlays feel more consistent and their content/actions line up more cleanly.\n- Debug builds now use separate runtime/config paths from normal releases, which avoids local development sessions colliding with your main herdr install.\n\n### Fixed\n- Starting a second herdr instance against an active socket now fails fast with a clear error instead of clobbering the running session.\n- Fixed pane and agent state updates being dropped under internal event queue pressure, which could leave a pane showing stale status after work finished.\n- Fixed onboarding modal sizing and click targets, and corrected release-notes scroll calculations when a scrollbar is present.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.3.1/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.3.1/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.3.1/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.3.1/herdr-macos-aarch64" - } - }, - "0.3.0": { - "notes": "### Major Changes\n- Added tabs within workspaces, so a single workspace can now hold multiple terminal tab contexts with their own pane layouts.\n- Added first-class tab support to the local socket API and CLI wrappers, including `herdr tab ...` commands and tab ids like `1:2` alongside workspace-scoped pane ids.\n- Added built-in direct integrations for pi, claude code, codex, and opencode, plus authoritative hook-driven state reporting so supported agents can report semantic state directly instead of relying only on screen heuristics.\n- Added a post-update release-notes screen so herdr can explain what changed after an update is installed.\n\n### UX and Controls\n- Added optional direct pane-focus keybindings for terminal mode, so you can switch panes with modifier shortcuts like `alt+h` or `alt+right` without entering navigate mode first.\n- Reworked keybind discoverability so the in-app keybind help now shows all supported actions, including optional bindings that are currently unset.\n- Keybind help now uses a centered scrollable modal with mouse and keyboard scrolling, matching the release-notes interaction model more closely.\n- Popups and action-button interactions now use more consistent modal geometry and button semantics across the UI.\n- Polished the sidebar agent section so it focuses on detected agents only and uses clearer two-line agent cards with more breathing room.\n\n### Behavior Fixes\n- Hook-driven agent state updates now stay correct in tabbed workspaces.\n- Modifier-only keypresses no longer leak into panes as stray input.\n- Multi-tab agent labels now include tab names when that extra context matters.\n- Workspace identity now follows the first tab's root pane again instead of stale creation-time cwd.\n- Background notification suppression is now tab-aware rather than workspace-wide, so background tabs in the current workspace can still alert correctly.\n\n### Documentation\n- Updated the README, configuration guide, integrations guide, skill, and socket API docs to reflect tabs, direct integrations, unset optional keybindings, direct terminal-mode navigation examples, workspace-scoped pane ids, and the current workspace identity/sidebar model.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.3.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.3.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.3.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.3.0/herdr-macos-aarch64" - } - }, - "0.2.4": { - "notes": "### Fixed\n- Fixed a macOS-only startup misdetection where pi could briefly appear as codex in the sidebar because process environment entries were being parsed as command-line arguments.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.4/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.4/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.4/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.4/herdr-macos-aarch64" - } - }, - "0.2.3": { - "notes": "### Changed\n- Mouse wheel handling now follows the tmux/Ghostty model more closely: fullscreen apps receive wheel input when they own scrolling, while herdr keeps host scrollback for panes that are behaving like a normal terminal transcript.\n- Pane scrollbars now only appear when herdr has real host scrollback for that pane, instead of implying a host-managed scroll position for app-owned scrolling.\n\n### Fixed\n- Fixed Codex and pi panes becoming unscrollable in herdr by preserving recoverable host history for top-anchored normal-screen output, without relying on alternate-screen scrollback retention.\n- Fixed pane wheel routing so apps using mouse reporting or alternate-scroll behavior can receive scroll input directly instead of having herdr always intercept it.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.3/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.3/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.3/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.3/herdr-macos-aarch64" - } - }, - "0.2.2": { - "notes": "### Fixed\n- Fixed pane scrollbars so they reserve their own lane instead of drawing over terminal content, which makes scrolling and scrollbar dragging behave more cleanly in narrow panes.\n- Fixed alternate-screen scrollback handling so full-screen terminal apps can preserve recoverable history inside herdr panes instead of losing rows that scroll off.\n- Fixed Codex in herdr panes losing transcript/history while running in alternate screen, so past output remains scrollable instead of disappearing as the session grows.\n- Hid the rendered terminal cursor while a pane is scrolled back, avoiding stray cursor blocks appearing in the wrong place during history navigation.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.2/herdr-macos-aarch64" - } - }, - "0.2.1": { - "notes": "### Added\n- Herdr now checks for updates at startup and periodically while it stays open, so long-running sessions can still discover new releases without a restart cycle.\n- Added a lightweight bottom-right toast when an update has been downloaded and is ready, with a simple restart-to-use-it flow.\n\n### Changed\n- Rendering is now driven more directly by app events instead of relying as much on polling, which makes the UI feel snappier and cuts unnecessary redraw work.\n\n### Fixed\n- Restored smooth fast spinner animation for working agents.\n- Closing a pane or workspace now reliably terminates the processes running inside that pane session instead of leaving shells or child processes behind.\n- Fixed bracketed paste handling so incomplete paste sequences are preserved across read timeouts instead of being dropped or misread.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.1/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.1/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.1/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.1/herdr-macos-aarch64" - } - }, - "0.2.0": { - "notes": "### Added\n- Added a local Unix socket API for controlling running herdr sessions, including workspace and pane management, pane reads, text/key input, pane splitting, and output waits.\n- Added event subscriptions over the socket API for workspace and pane lifecycle events, pane output matches, and agent state changes.\n- Added CLI wrappers on top of the socket API with `herdr workspace ...`, `herdr pane ...`, and `herdr wait ...`, using compact public ids like `1` and `1-2` for scripting and agent orchestration.\n- Added a settings popup with mouse support for changing themes, sound alerts, and toast notifications from inside herdr.\n- Added 9 built-in themes: catppuccin, tokyo night, dracula, nord, gruvbox, one dark, solarized, kanagawa, and ros\u00e9 pine.\n- Added interactive pane scrollbars, manual sidebar resizing, and upstream git ahead/behind indicators in the workspace sidebar.\n\n### Changed\n- Redesigned the sidebar into a two-section layout that separates workspace-level triage from per-agent detail, making it easier to supervise multiple agents in parallel.\n- Agent state names exposed in the UI and integration surfaces now use `working` and `blocked`.\n- Herdr now blocks nested launches by default when started inside a herdr-managed pane; set `advanced.allow_nested = true` to opt back in.\n\n### Fixed\n- Improved terminal keyboard protocol parsing and input forwarding across terminal variants, including better handling for shifted printable keys.\n- Fixed Ghostty on macOS misparsing some arrow-key and modifier/enhanced key sequences.\n- Refined sidebar rollups and pane ordering so workspace status and agent lists stay more stable and predictable.\n\n### Documentation\n- Refreshed the README, socket API reference, and reusable agent skill docs to better explain herdr's agent multiplexer model and integration surface.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.2.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.2.0/herdr-macos-aarch64" - } - }, - "0.1.2": { - "notes": "### Added\n- Added first-run onboarding flow that lets you choose notification preferences (sound and toast) on startup.\n- Added optional visual toast notifications in the top-right corner for background workspace events (completion and attention-needed alerts).\n- Added configurable keybindings for all navigate mode actions: new workspace, rename workspace, close workspace, resize mode, and toggle sidebar. See the [configuration docs](https://herdr.dev/docs/configuration/) for the full key reference.\n- Added configuration validation with startup diagnostics. Invalid key combinations or duplicate bindings now fall back to safe defaults with a visible warning.\n\n### Changed\n- **Breaking:** Default prefix key changed from `ctrl+s` to `ctrl+b` to avoid common terminal flow control conflicts.\n- Workspaces now derive their identity from the repository or folder of their root pane, updating automatically as you navigate. Custom names act as overrides rather than static labels.\n- Sidebar now shows workspace numbers again in expanded view.\n- Refined sidebar presentation with consistent marker/name/state ordering and comma-separated agent summaries.\n- Keybinding parser now accepts special keys (`enter`, `esc`, `tab`, `backspace`, `space`) and function keys (`f1`\u2013`f12`).\n\n### Documentation\n- Split configuration reference into dedicated configuration docs with full keybinding documentation and config diagnostics explanation.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.1.2/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.1.2/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.1.2/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.1.2/herdr-macos-aarch64" - } - }, - "0.1.1": { - "notes": "### Added\n- Added optional sound notifications for agent state changes, including a completion chime when background work finishes and an alert when an agent needs input.\n- Added per-agent sound overrides under `[ui.sound.agents]`, so you can mute or enable notifications by agent instead of using one global setting. Droid notifications are muted by default.\n\n### Changed\n- Request alerts now play even when the agent is in the active workspace, while completion sounds remain limited to background workspaces.\n\n### Fixed\n- Improved foreground job detection on Linux and macOS so herdr can recognize agents that run through wrapper processes or generic runtimes, including cases like Codex running under `node`.\n- Made Claude Code state detection more stable by handling more spinner variants and smoothing short busy/idle flicker during screen updates.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.1.1/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.1.1/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.1.1/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.1.1/herdr-macos-aarch64" - } - }, - "0.1.0": { - "notes": "### Added\n- Initial release.", - "assets": { - "linux-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.1.0/herdr-linux-x86_64", - "linux-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.1.0/herdr-linux-aarch64", - "macos-x86_64": "https://github.com/herdrdev/herdr/releases/download/v0.1.0/herdr-macos-x86_64", - "macos-aarch64": "https://github.com/herdrdev/herdr/releases/download/v0.1.0/herdr-macos-aarch64" - } - } - } -} 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/preview.json b/website/preview.json deleted file mode 100644 index 806852e6..00000000 --- a/website/preview.json +++ /dev/null @@ -1,829 +0,0 @@ -{ - "schema_version": 1, - "channel": "preview", - "base_version": "0.8.2", - "build_id": "2026-08-31-b1ff4582e968", - "commit": "b1ff4582e9688f52ffb943cfa8bee4871ae122e4", - "built_at": "2026-08-31T15:59:38Z", - "protocol": 21, - "notes": "Preview build 2026-08-31-b1ff4582e968\n\nBuilt from `b1ff4582e968` on `master`.\nBase stable: v0.8.2\nCompare: https://github.com/herdrdev/herdr/compare/b5c4a0176e9183924df552eb8aecb94ed5f9e732...b1ff4582e9688f52ffb943cfa8bee4871ae122e4\n\n### Added\n- Add muse agent with generic Pick blocked detection (#2489)\n- Add per-mode theme overrides (#2324)\n\n### Fixed\n- Detect pi bundled cli (#3207)\n- Make test-one work on Windows (#3442)\n- Detect copilot background agents as working (#3403)\n- Encode antigravity windows hook command (#3352)\n- Report the foreground group leader's cwd, not a descendant's (#3386)\n- Reject oversized git ref files in workspace status reads (#3373)\n- Detect claude mcp elicitation dialogs as blocked (#3383)\n- Handle associated text on special keys (#3350)\n- Keep OSC evidence through first agent acquisition (#3326)\n- Trust worktree repositories per request (#3344)\n- Ignore cursor events in claude hooks (#3342)\n- Ignore codex weak blockers above the current prompt (#3339)\n- Require explicit workspace group close (#3206)\n- Accept reordered agent report arguments (#2928)\n- Route osc 8 file links to plugin handlers (#2942)\n- Keep wayland clipboard copies responsive (#3015)\n- Report agent explain file errors as json (#3023)\n- Refresh shared agent manifest caches (#3204)\n- Batch kitty image row lifecycle (#3166)\n- Serve a google-eligible favicon\n- Keep omp panes working through scheduled continuations (#3122)\n- Start lifecycle subscriptions from live events (#3134)\n- Add local cmd installer bootstrap (#3133)\n- Preserve non-us shifted text (#3055)\n- Clear Windows Terminal identity in panes (#3127)\n- Copy selections before delayed mouse release (#3102)\n- Preserve focus after background worktree removal (#3099)\n- Publish Claude MCP detection manifest\n- Match generated characters in prefix bindings (#3085)\n- Keep background Claude MCP tasks working (#3094)\n- Preserve multiline paste in terminal attach (#3056)\n- Isolate oversized kitty images (#3035)\n- Detect cursor bundled node process (#3034)\n- Add claude screen activity fallbacks\n- Synchronize plugin pane pwd (#2985)\n- Honor mouse capture config in terminal attach (#2995)\n- Preserve mouse forwarding through handoff (#3002)\n- Strip ansi sequences from tab bar status (#3003)\n\n### Maintenance\n- Trigger ai reviews and add maintainer\n- Restrict release workflows to canonical repository\n- Move changelog curation to release prep\n- Document macos keychain launch context\n- Keep kennel authority private\n- Pin kennel maintainer identities\n- Use native path in docs parity assertion (#3043)\n- Remove akbash maintainer authority\n- Support immutable preview releases\n- Publish preview documentation", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-linux-x86_64", - "sha256": "61c1c9181c0cf62a00882f21f2c6e19ce8ee6360410736a4c6c5a1387a0fc388" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-linux-aarch64", - "sha256": "32609bf5f564aaafe951a79cf8e51163319f82bfad8e8c3877b87938a5952a43" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-macos-x86_64", - "sha256": "b00cc237c04fecaa3385a80d38d3352483a4250cbf21edef37a1c2fa3019ddce" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-macos-aarch64", - "sha256": "93bb174c2962e1282a0fa4df5f986956a4253e08aaf7eecdca3d919d2704106b" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-windows-x86_64.zip", - "sha256": "e35e9d92a9f77c559cf814f36d0e5f6e66ab3a6f61eadac58ab5be9bb9223f7e", - "format": "zip" - } - }, - "builds": { - "2026-08-31-b1ff4582e968": { - "base_version": "0.8.2", - "commit": "b1ff4582e9688f52ffb943cfa8bee4871ae122e4", - "built_at": "2026-08-31T15:59:38Z", - "protocol": 21, - "tag": "preview-2026-08-31-b1ff4582e968", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-linux-x86_64", - "sha256": "61c1c9181c0cf62a00882f21f2c6e19ce8ee6360410736a4c6c5a1387a0fc388" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-linux-aarch64", - "sha256": "32609bf5f564aaafe951a79cf8e51163319f82bfad8e8c3877b87938a5952a43" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-macos-x86_64", - "sha256": "b00cc237c04fecaa3385a80d38d3352483a4250cbf21edef37a1c2fa3019ddce" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-macos-aarch64", - "sha256": "93bb174c2962e1282a0fa4df5f986956a4253e08aaf7eecdca3d919d2704106b" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-31-b1ff4582e968/herdr-windows-x86_64.zip", - "sha256": "e35e9d92a9f77c559cf814f36d0e5f6e66ab3a6f61eadac58ab5be9bb9223f7e", - "format": "zip" - } - } - }, - "2026-08-19-b5c4a0176e91": { - "base_version": "0.8.2", - "commit": "b5c4a0176e9183924df552eb8aecb94ed5f9e732", - "built_at": "2026-08-19T19:32:11Z", - "protocol": 20, - "tag": "preview-2026-08-19-b5c4a0176e91", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-19-b5c4a0176e91/herdr-linux-x86_64", - "sha256": "fe5d3009003113731bfe1e7a72b356acaf2d6e35aee952aa68ecb4fd63710d8c" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-19-b5c4a0176e91/herdr-linux-aarch64", - "sha256": "4d9175d8cd377537f5f70c96fade62b2493cce1fa097ae2edf39d5c4168d7b6e" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-19-b5c4a0176e91/herdr-macos-x86_64", - "sha256": "7133b614f07b40979b1eca3a4607e9242ed6cd9ff988e0c17c7d8c8b5f5f05b3" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-19-b5c4a0176e91/herdr-macos-aarch64", - "sha256": "61fe8e4e2ebe82c0267ab2ecb0c996847627be2c69c41aea12a445675c7cb097" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-19-b5c4a0176e91/herdr-windows-x86_64.zip", - "sha256": "01c8bc9f22be0ad447ceb8f4ed8ae18871b31694ccfd6b504b26ee31f0c6e25e", - "format": "zip" - } - } - }, - "2026-08-18-9fac51722653": { - "base_version": "0.8.0", - "commit": "9fac51722653fa0b0b6a5786166fb18c763424e0", - "built_at": "2026-08-18T19:40:21Z", - "protocol": 20, - "tag": "preview-2026-08-18-9fac51722653", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-18-9fac51722653/herdr-linux-x86_64", - "sha256": "92a164e247142c190f01352cd15d894633dca77e3326efd5850c33319ee2e986" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-18-9fac51722653/herdr-linux-aarch64", - "sha256": "901a06de8ece0b4b54c1071b923f22e9e68af0b472ea0cd4403faf313b4dbe52" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-18-9fac51722653/herdr-macos-x86_64", - "sha256": "2ecae0f0df52e5588fd0bdc78c41a2b867100592bb7a3d7bfe192957c0fc7499" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-18-9fac51722653/herdr-macos-aarch64", - "sha256": "e91ccc7004db186a64c78bfe902e1ee6fdb0a0003bf2a480f705926511006d24" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-18-9fac51722653/herdr-windows-x86_64.zip", - "sha256": "e40ed68a771e0d292c57ce2f1e8432c55ba939a566827b6b652fca5241167c88", - "format": "zip" - } - } - }, - "2026-08-17-1147e60bc0a4": { - "base_version": "0.8.0", - "commit": "1147e60bc0a43c727563bee457394af0ca0a5e8b", - "built_at": "2026-08-17T14:20:40Z", - "protocol": 20, - "tag": "preview-2026-08-17-1147e60bc0a4", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-17-1147e60bc0a4/herdr-linux-x86_64", - "sha256": "e715da1007455e5392a5267c937cedeb81029e35e7078b12184f2b04a9c185df" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-17-1147e60bc0a4/herdr-linux-aarch64", - "sha256": "dda8f1439052333ef4d5ce529b783574c0d591829fe36a6569fe22414761285c" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-17-1147e60bc0a4/herdr-macos-x86_64", - "sha256": "58486d4e5c622af674962071de13383f8c5bc82f08d8ebdc3df47dea54daee2b" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-17-1147e60bc0a4/herdr-macos-aarch64", - "sha256": "4ffd50b4b06e6c6bbda1f98fa6220f199c7cfceb2f0f20a8ad0874638115c0c5" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-17-1147e60bc0a4/herdr-windows-x86_64.zip", - "sha256": "631cbbd7fe1450eeb198038088d4d56dd5f0779b3e267f99b7770ad604b36677", - "format": "zip" - } - } - }, - "2026-08-04-d78e3d3b5126": { - "base_version": "0.8.0", - "commit": "d78e3d3b51266a1ff80ae6858b894e782aac3e9f", - "built_at": "2026-08-03T21:56:43Z", - "protocol": 19, - "tag": "preview-2026-08-04-d78e3d3b5126", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-04-d78e3d3b5126/herdr-linux-x86_64", - "sha256": "338afbfe03f0eb32efc52e30a5effc6c5ee772846bdb5e059f73d04b89b467d6" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-04-d78e3d3b5126/herdr-linux-aarch64", - "sha256": "f79f3ad5b24dd1b6ba49ebee1b26d69ab5dcbeaf15be4fd7f3357ab0d17f6096" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-04-d78e3d3b5126/herdr-macos-x86_64", - "sha256": "384ee2f2a805260d24f3d398ba8169aa68b502452ab1457c5da40a8e4d9c975f" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-04-d78e3d3b5126/herdr-macos-aarch64", - "sha256": "d02190962293ccf19186e0ea8a162d7f670ef49e61dfc10051bffd7da08a7ee4" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-08-04-d78e3d3b5126/herdr-windows-x86_64.zip", - "sha256": "b1d288118848ecd3ef33532a34506edc53a38a416057aee5b7fe1de4188a16fc", - "format": "zip" - } - } - }, - "2026-07-29-44b3adb12552": { - "base_version": "0.7.5", - "commit": "44b3adb125524ea9a55739eee3776f922f2115ad", - "built_at": "2026-07-29T13:32:08Z", - "protocol": 18, - "tag": "preview-2026-07-29-44b3adb12552", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-29-44b3adb12552/herdr-linux-x86_64", - "sha256": "2d50d64ab849c3d0f5d0d53e0bebd00fa94d5ed120797532c8fcfd1a679ebc19" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-29-44b3adb12552/herdr-linux-aarch64", - "sha256": "2167fb9127d0a67c1dad368d54e6468fd7c2a3858b832922c7f0c264d012be13" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-29-44b3adb12552/herdr-macos-x86_64", - "sha256": "b9316cdff4802f325f6b77b83ea36cd33deb8da4ef9efa8454423b0ce8de77fc" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-29-44b3adb12552/herdr-macos-aarch64", - "sha256": "99941b4a40e852c8f21694c7ec1e96f85abd4f764d9f667757c65fae6e4b065b" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-29-44b3adb12552/herdr-windows-x86_64.zip", - "sha256": "ead450c21d31ea559289d45e4c60d14bb0a7ff0937668a309e74c6a3f9f6cca1", - "format": "zip" - } - } - }, - "2026-07-21-0f10e1453a7f": { - "base_version": "0.7.5", - "commit": "0f10e1453a7f9fda357352bb65ce17fa26fda447", - "built_at": "2026-07-21T18:47:44Z", - "protocol": 17, - "tag": "preview-2026-07-21-0f10e1453a7f", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-21-0f10e1453a7f/herdr-linux-x86_64", - "sha256": "f2d4e50e7e2492bb1a6707b2e42aa27344ceb1ec2dec3f870caa8b5223a875eb" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-21-0f10e1453a7f/herdr-linux-aarch64", - "sha256": "1ff9d07c0ad13e5fede74cbd2cdc79021ffafd9efcd669851c996b7e528150c6" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-21-0f10e1453a7f/herdr-macos-x86_64", - "sha256": "4b4952618ba3491439f14dd2e84d43a37aa320cbb57103bcf647c110225922ad" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-21-0f10e1453a7f/herdr-macos-aarch64", - "sha256": "5ce638f8891db503bf7a4cd25464188c9275b9fea9e9bee0615ed8ba42a9191c" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-21-0f10e1453a7f/herdr-windows-x86_64.exe", - "sha256": "75c85763db0ca5fd13b485d0728cc3e9ea1152964a4e976e1d49f2e86b01a92b" - } - } - }, - "2026-07-17-813fec141faa": { - "base_version": "0.7.4", - "commit": "813fec141faabe0615b66c4f1738c0af7581309c", - "built_at": "2026-07-17T13:28:57Z", - "protocol": 16, - "tag": "preview-2026-07-17-813fec141faa", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-17-813fec141faa/herdr-linux-x86_64", - "sha256": "9ef34a56091f5b3e2054c2a8e6aabd9056fe22e2fad36147a51ec8dc8f4fde73" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-17-813fec141faa/herdr-linux-aarch64", - "sha256": "d1fc0ddd3ce161a5718131b9fde063846ca1348bde50abf71d5e01a43fd93d8d" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-17-813fec141faa/herdr-macos-x86_64", - "sha256": "f0c2541c3a21cccd95173b5e9356884415e41b77aeb66c536324fa70227b5598" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-17-813fec141faa/herdr-macos-aarch64", - "sha256": "9103b90851242053a4778d5e16364c1afd178a2a2f6cf8c1705f0e75b4c470b3" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-17-813fec141faa/herdr-windows-x86_64.exe", - "sha256": "2b53a21755d6393515f84c246b6297d46103e7e741714bcf2244b408c1178d57" - } - } - }, - "2026-07-16-e907e6a36646": { - "base_version": "0.7.4", - "commit": "e907e6a3664608b34351344dfdfbc0431dab8760", - "built_at": "2026-07-16T17:16:52Z", - "protocol": 16, - "tag": "preview-2026-07-16-e907e6a36646", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-16-e907e6a36646/herdr-linux-x86_64", - "sha256": "d0f0da4068a902c0ffc0ca1104df1e6e608cff75c16701cef84f1a71aa770a26" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-16-e907e6a36646/herdr-linux-aarch64", - "sha256": "e4211681df4eaaebf05e1917f58bb38f5487a7f6c17057b596382ccb5fffe879" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-16-e907e6a36646/herdr-macos-x86_64", - "sha256": "cebe6f87f9f03a4bf1c2d6c315d8ab6bcd16d838471164e5cb12862c57cece8f" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-16-e907e6a36646/herdr-macos-aarch64", - "sha256": "f75f6afb79b04807d7295114357612048eea16eaf9a7e8871dbb1ffda6d1fdca" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-16-e907e6a36646/herdr-windows-x86_64.exe", - "sha256": "a5827b33cbd0352e4c0f1469ca6e0f71083e1333cf0250ca9dbecc41770a6d30" - } - } - }, - "2026-07-15-50aaa2ec046e": { - "base_version": "0.7.4", - "commit": "50aaa2ec046ee26ff407c20f49de496f522512a8", - "built_at": "2026-07-15T19:27:16Z", - "protocol": 16, - "tag": "preview-2026-07-15-50aaa2ec046e", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-15-50aaa2ec046e/herdr-linux-x86_64", - "sha256": "9ba11e56ace4286077ef279a86476f6f2f81f2faf0280f1e56249b6f4bc4b160" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-15-50aaa2ec046e/herdr-linux-aarch64", - "sha256": "11ef0d1a64b097e479f95e2578c2fee4e11d208640a6a98ea70ade968d145c7a" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-15-50aaa2ec046e/herdr-macos-x86_64", - "sha256": "b1817355df28be4fd725d1795577e400f8edd90d3e807224b508a0c8e628c3ef" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-15-50aaa2ec046e/herdr-macos-aarch64", - "sha256": "e1aa34cc33b3a30be4a5a5fd04bebf05c2011e4fb095f5ff20340eb200b5a1f9" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-15-50aaa2ec046e/herdr-windows-x86_64.exe", - "sha256": "1d99fa64974a69aa451230ba0c356c8466a4fb96fecb933abf81dd00f6dfc90e" - } - } - }, - "2026-07-07-f5354780e4ef": { - "base_version": "0.7.2", - "commit": "f5354780e4efcc938861b04992e954df915a07c8", - "built_at": "2026-07-07T20:42:48Z", - "protocol": 16, - "tag": "preview-2026-07-07-f5354780e4ef", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-07-f5354780e4ef/herdr-linux-x86_64", - "sha256": "d5bc1b05c7d6f7ad9a00cc251b840aaac09026dcacaf6cf9dd51fc6e72cbe319" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-07-f5354780e4ef/herdr-linux-aarch64", - "sha256": "76787f396f4d791f4900c1277ab4758a3c995abb2fa0e0c458bf7158ca31af46" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-07-f5354780e4ef/herdr-macos-x86_64", - "sha256": "7b70ca227b1265fce74cd1079257905a3061c53b8f43fdf9944ea1a0d7acf1df" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-07-f5354780e4ef/herdr-macos-aarch64", - "sha256": "ccf23f9d057d8bee8da1868bd26726971a556b344e151a33772967aa3da47d1d" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-07-f5354780e4ef/herdr-windows-x86_64.exe", - "sha256": "9b28eb0a3a55ca2ca9d47e96397544d2cbcca965d88a40b8bd8ccacfb61333ba" - } - } - }, - "2026-07-06-4dae557eefd9": { - "base_version": "0.7.1", - "commit": "4dae557eefd992cbc03d435c6265842611811a67", - "built_at": "2026-07-06T12:17:00Z", - "protocol": 16, - "tag": "preview-2026-07-06-4dae557eefd9", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-06-4dae557eefd9/herdr-linux-x86_64", - "sha256": "89cdcb7303b2461ed53659c1e27cabc40eb1c4d7f4014bc0d3420c7884cbdfb0" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-06-4dae557eefd9/herdr-linux-aarch64", - "sha256": "10dc280b5df1f889d529986fbfbd2c15b6ad5104413ad5f9ea27b353321230a2" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-06-4dae557eefd9/herdr-macos-x86_64", - "sha256": "682a9ac9eb9c23d35bb4dcf34089dc9fbdc0872e60763463c874e7207f400a73" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-06-4dae557eefd9/herdr-macos-aarch64", - "sha256": "5d02f2f30377c1790bee0a24c38532377cf67f5c8d009302b120406c48a7a796" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-07-06-4dae557eefd9/herdr-windows-x86_64.exe", - "sha256": "7c2189c218d210fa253e579c3d50b9c501cb16c3d3729e1de3dba366c5773a14" - } - } - }, - "2026-06-30-3459798b606d": { - "base_version": "0.7.1", - "commit": "3459798b606d019d4ac404d407af956d7539ef54", - "built_at": "2026-06-30T17:57:27Z", - "protocol": 15, - "tag": "preview-2026-06-30-3459798b606d", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-30-3459798b606d/herdr-linux-x86_64", - "sha256": "0302d856719ccc6e41288d2640db7361e3c2e63047d75c14d4da96177fdd76fe" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-30-3459798b606d/herdr-linux-aarch64", - "sha256": "e48a407a4276491ef946f093c5a789adc53b369a78e40e7ef322b9a094db78a4" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-30-3459798b606d/herdr-macos-x86_64", - "sha256": "69558cfb8afaef115d0a0a78c3b7424a1f5f2469ae8d19a2fef39af0ee10fffe" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-30-3459798b606d/herdr-macos-aarch64", - "sha256": "eaa330fdb016de2130237d353371444561e6027ad19ab4e752546b81ce14c71a" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-30-3459798b606d/herdr-windows-x86_64.exe", - "sha256": "9e319d9d7d653fa4cc7d775e1f653886dd4080b64516ea6bf2ef4d64b33cf891" - } - } - }, - "2026-06-25-7811d84f15f1": { - "base_version": "0.7.1", - "commit": "7811d84f15f1b2e41d68901d368791b15e0bf6c7", - "built_at": "2026-06-25T14:34:05Z", - "protocol": 14, - "tag": "preview-2026-06-25-7811d84f15f1", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-25-7811d84f15f1/herdr-linux-x86_64", - "sha256": "b366db1c3aae2990b242d2ecfda1b903aa4638ce036fd4947be9c1cf210c82d6" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-25-7811d84f15f1/herdr-linux-aarch64", - "sha256": "ad8c912720d8e2eb70bbf41505d76a46113dcf5f528eb4ba60d5e0af06548e87" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-25-7811d84f15f1/herdr-macos-x86_64", - "sha256": "6ebecb5085f42a3adc88e9031d7567b274650f8d5fae6f1efa7a3d49e86119ab" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-25-7811d84f15f1/herdr-macos-aarch64", - "sha256": "6adb29e6fc129ac21a5f021b8410e6e9bdae9e7fc4342a3c0d602cc725a12dfe" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-25-7811d84f15f1/herdr-windows-x86_64.exe", - "sha256": "6d45a5dacd471877b4c34ca4a6a33e3cd1e3ecf2adc72f1216eb15e6e7c5a0f6" - } - } - }, - "2026-06-22-24c7377de01c": { - "base_version": "0.7.0", - "commit": "24c7377de01c4f49e4c9a95761058252bfb53227", - "built_at": "2026-06-22T12:02:59Z", - "protocol": 14, - "tag": "preview-2026-06-22-24c7377de01c", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-22-24c7377de01c/herdr-linux-x86_64", - "sha256": "c233227d6f883fe7841df43d50606faff6aa4eb5861f1057aafea447289ef49b" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-22-24c7377de01c/herdr-linux-aarch64", - "sha256": "c8684d650e20e1b2adb62076a25dc5d6ecb2db72e128c19b52b97b6e91bf7778" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-22-24c7377de01c/herdr-macos-x86_64", - "sha256": "36dced19de4cbcfdd2d92a900a07e8c49d8fe239585ac3973f8d654f3a708534" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-22-24c7377de01c/herdr-macos-aarch64", - "sha256": "04988b316d53a0b153c368bed1a69d8adf1a219fab5c2db18c5b7c1358739f65" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-22-24c7377de01c/herdr-windows-x86_64.exe", - "sha256": "9eb8b028d92770c0b0c39e8c5e3edd75a8ea8592473c4d1e4396e84d769a9781" - } - } - }, - "2026-06-15-517ca8163f7c": { - "base_version": "0.7.0", - "commit": "517ca8163f7c313bdeef565bdcb9b055ce05526c", - "built_at": "2026-06-15T18:09:54Z", - "protocol": 14, - "tag": "preview-2026-06-15-517ca8163f7c", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-15-517ca8163f7c/herdr-linux-x86_64", - "sha256": "83813cb9d154e394cfa9ccd0c0bce958ad43a4f276e7343b38f95a829ca7f2b7" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-15-517ca8163f7c/herdr-linux-aarch64", - "sha256": "fe27f63d437e5aa9708e9767a7354b3f59d4f901794caa6d6731c2ddd98f9724" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-15-517ca8163f7c/herdr-macos-x86_64", - "sha256": "f624cd1ca8a8742cf0ae8eb090b814ef1c5b905d83da4142f1a34e7db3bc77ec" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-15-517ca8163f7c/herdr-macos-aarch64", - "sha256": "7b374b436c12b745e697229c5e1195ef011e4ed93ebb388eaa49c7b630f80f12" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-15-517ca8163f7c/herdr-windows-x86_64.exe", - "sha256": "9dd44fd4fb788e56e2049710f73545a7199c4eadfba4da96634e84671e5ee35a" - } - } - }, - "2026-06-12-7ba4bfe90e7a": { - "base_version": "0.6.10", - "commit": "7ba4bfe90e7a17b11979e729d29d82723bb3b0bf", - "built_at": "2026-06-12T04:34:21Z", - "protocol": 13, - "tag": "preview-2026-06-12-7ba4bfe90e7a", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-12-7ba4bfe90e7a/herdr-linux-x86_64", - "sha256": "08e89f24f105373f8ec0a335bf9234adf455b8392662bbbf8b53436f1beaa3b7" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-12-7ba4bfe90e7a/herdr-linux-aarch64", - "sha256": "cb01c595603330194bee4ccaf8e3ba24076391d504fb5b85b2effe0aff352152" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-12-7ba4bfe90e7a/herdr-macos-x86_64", - "sha256": "0d7a33c2c5d7734b3fff88717fca45b24de45a5e438ea90b1ccfb214ab314022" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-12-7ba4bfe90e7a/herdr-macos-aarch64", - "sha256": "4de019156ce125a7bd6b03d609b887db161d199ecae95d4762f4c9179ba31bc4" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-12-7ba4bfe90e7a/herdr-windows-x86_64.exe", - "sha256": "8611f6f295da398d4601433e69a1f227d1bba5b38b31504331b9e3a2e31ade87" - } - } - }, - "2026-06-10-7d6eaf5f26d1": { - "base_version": "0.6.8", - "commit": "7d6eaf5f26d1fa93b9c95c0457d43183f989fab9", - "built_at": "2026-06-10T18:28:20Z", - "protocol": 13, - "tag": "preview-2026-06-10-7d6eaf5f26d1", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-7d6eaf5f26d1/herdr-linux-x86_64", - "sha256": "02e9ec811e6ad27471d6fb1eaca0441d77c8ebc1cb5ac406d57749263e78cac1" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-7d6eaf5f26d1/herdr-linux-aarch64", - "sha256": "ef9c706aabdf075bc838decac8e39e99704ad91c589cec4f003d01bbae9bafd0" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-7d6eaf5f26d1/herdr-macos-x86_64", - "sha256": "2f6e07147ca1015c0e454a2256118d4cb9222ba4eb921bf11ef8fe369a4386fa" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-7d6eaf5f26d1/herdr-macos-aarch64", - "sha256": "1b06ecfd20891138b4e0e5b58e9a4eb322d858a1a524d14372936666a0a96792" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-7d6eaf5f26d1/herdr-windows-x86_64.exe", - "sha256": "bba72ef9f761fd07d3380800fa704b19f4a6cc03da40f1ac33fecbf1bf9d884b" - } - } - }, - "2026-06-10-38f3b290deed": { - "base_version": "0.6.8", - "commit": "38f3b290deed3008b52c11589a1048b227702894", - "built_at": "2026-06-10T04:33:50Z", - "protocol": 13, - "tag": "preview-2026-06-10-38f3b290deed", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-38f3b290deed/herdr-linux-x86_64", - "sha256": "f807d0c66b1dd93d9935b96c2673a842bb0d0e75658aed879d215855007d5e9f" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-38f3b290deed/herdr-linux-aarch64", - "sha256": "8fd10ad9104d9a2ef84c01cbc4c5b56573baf6ecb019d31c9cfe3deb6536fb63" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-38f3b290deed/herdr-macos-x86_64", - "sha256": "1b64c7230f27bcfcc3f0fa568bb5682e07482e2fbe611f570b3190cda51e4fe6" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-38f3b290deed/herdr-macos-aarch64", - "sha256": "72cc7201b7b31debe22b478f9f702dcce007235af74c9deed3fa8170d72943ed" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-10-38f3b290deed/herdr-windows-x86_64.exe", - "sha256": "f52a8b99b1d4c49639af05d1998d1fe870eb110fd1d786dc67963ad5b77c2739" - } - } - }, - "2026-06-09-3e2bdbab7b05": { - "base_version": "0.6.8", - "commit": "3e2bdbab7b05c042d47caaf355be1f2f25b624fb", - "built_at": "2026-06-09T13:18:23Z", - "protocol": 13, - "tag": "preview-2026-06-09-3e2bdbab7b05", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-09-3e2bdbab7b05/herdr-linux-x86_64", - "sha256": "5eeecb77185b11e7108e34430c3f335cec5396d0c3b0b4590beb50a6ec590a21" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-09-3e2bdbab7b05/herdr-linux-aarch64", - "sha256": "9a7ca191adeab1e1400584090ce58c1cf0dc02951b881e4220f3c97dda334a5c" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-09-3e2bdbab7b05/herdr-macos-x86_64", - "sha256": "d6f7c7a293e411caa8d74f240f49ff605977a6a24809a9689c6bd0504e1c96ee" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-09-3e2bdbab7b05/herdr-macos-aarch64", - "sha256": "83d915384444e1ff19ccf06dfad96a31877a68bceed82d8b07234d5690011222" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-09-3e2bdbab7b05/herdr-windows-x86_64.exe", - "sha256": "c88561dc574158d95e12cdb887d52a40916911dd33a187eced1735522977bc4a" - } - } - }, - "2026-06-07-3c8f8dcb7774": { - "base_version": "0.6.8", - "commit": "3c8f8dcb7774fa07d6e8e2972e3b70cd5ca375ca", - "built_at": "2026-06-07T17:27:16Z", - "protocol": 13, - "tag": "preview-2026-06-07-3c8f8dcb7774", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3c8f8dcb7774/herdr-linux-x86_64", - "sha256": "f29bc4a93b417e4c8e7d183555396e4a38072e2b0e09e4021f5ca6a54d5ccadc" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3c8f8dcb7774/herdr-linux-aarch64", - "sha256": "2ed8e9d00acfa97d612b0143b49cbe4f04a8080c5b12d57451d32a5dd34a31a3" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3c8f8dcb7774/herdr-macos-x86_64", - "sha256": "038a480634b16fd2dcc5cbaa982ad5dd60708067644f3566fb52e08bd343919e" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3c8f8dcb7774/herdr-macos-aarch64", - "sha256": "d46800e1a82761e4a14ae5391847a5247e410ad3de3cf71b5c7fd93c8b895846" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3c8f8dcb7774/herdr-windows-x86_64.exe", - "sha256": "d83fca4971afd7ecd8be1bb36a730611d6b9f461480d75084680afc2c8e84f2c" - } - } - }, - "2026-06-07-3f7236f81735": { - "base_version": "0.6.8", - "commit": "3f7236f81735e338e2ed3ecbf0f1fed26392acba", - "built_at": "2026-06-07T14:10:04Z", - "protocol": 13, - "tag": "preview-2026-06-07-3f7236f81735", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3f7236f81735/herdr-linux-x86_64", - "sha256": "b5e5e539bcc34e49ea8e443c8d94ebbaf6c644e0eb3e0a5a63e134c6ebcc6407" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3f7236f81735/herdr-linux-aarch64", - "sha256": "9dbf8047317fb86e3e61e00780dbdf6ff0344fc51f0d5da3dc49690bf29f80f9" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3f7236f81735/herdr-macos-x86_64", - "sha256": "8d2fa2e82564b6f23e92577832fa222c9099b1e8902123d0d1d7ba118e824614" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3f7236f81735/herdr-macos-aarch64", - "sha256": "1e202611df9f94e44af72cfa0975fafdaef19b514768d208a282f9f725ce8877" - }, - "windows-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-07-3f7236f81735/herdr-windows-x86_64.exe", - "sha256": "8a6a211edfb853615a39da8a03344a686e9bb28ee07080a8d17b116c5b1dbf13" - } - } - }, - "2026-06-05-1ce4213d9ebb": { - "base_version": "0.6.8", - "commit": "1ce4213d9ebb6149395743baa03e62baeaeeb10c", - "built_at": "2026-06-05T04:33:42Z", - "protocol": 12, - "tag": "preview-2026-06-05-1ce4213d9ebb", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-05-1ce4213d9ebb/herdr-linux-x86_64", - "sha256": "130478ead15570df80d4b71f35efb28be9da51958c2da438e0f766e76c6859fc" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-05-1ce4213d9ebb/herdr-linux-aarch64", - "sha256": "35bd06cf80afaab8ecac0b1f6dc3dd74775865f6a1d682575b33f7c3424c616b" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-05-1ce4213d9ebb/herdr-macos-x86_64", - "sha256": "1279ce4e1c5a73b3725af4e288153b3597aa3133a156588ce4f7f22d6b8a88d4" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-05-1ce4213d9ebb/herdr-macos-aarch64", - "sha256": "4bd46e2f4e3d76bf730b105fe11de53093c5b580b7e0a042359a887c5ac6aef0" - } - } - }, - "2026-06-04-670656b26f1a": { - "base_version": "0.6.8", - "commit": "670656b26f1aeadc3f18e6692a9fdf1b02da799c", - "built_at": "2026-06-04T19:48:01Z", - "protocol": 12, - "tag": "preview-2026-06-04-670656b26f1a", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-04-670656b26f1a/herdr-linux-x86_64", - "sha256": "24dbbcc8f56d0d6fb05f08b30b42034de10155f09326a9f535810d0f4d53812a" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-04-670656b26f1a/herdr-linux-aarch64", - "sha256": "8f3708274a4e56f613709d05b4b8d56ba8d7b3a10705c12f2b57899cc5ff105b" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-04-670656b26f1a/herdr-macos-x86_64", - "sha256": "1a24cc6793a61a70c5e9a52514b809d267adde795152dd236f854048a82aa4bf" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-04-670656b26f1a/herdr-macos-aarch64", - "sha256": "396c97c613f33e490f66c36456d47cfb34dd9aca50a5911ef0adf6e1914c6c4c" - } - } - }, - "2026-06-03-854fc3c1aff5": { - "base_version": "0.6.7", - "commit": "854fc3c1aff525913c180543bfc8741b81253da0", - "built_at": "2026-06-03T12:17:39Z", - "protocol": 12, - "tag": "preview-2026-06-03-854fc3c1aff5", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-854fc3c1aff5/herdr-linux-x86_64", - "sha256": "7513c0d40dda605c08c909e9652cdb30333900f4602a54c0eddb2e6878599fba" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-854fc3c1aff5/herdr-linux-aarch64", - "sha256": "a25b0d226e1c43bd11713e690e962c75a42ef528f9695dfbee4be7223eba8b33" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-854fc3c1aff5/herdr-macos-x86_64", - "sha256": "0ca3b10722c9077feabcc728e56a284fb24256fbe6ec01af60a1af582f9ff690" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-854fc3c1aff5/herdr-macos-aarch64", - "sha256": "ba2ac2ba89c46a328bb87f942cac7bc18d6d91c23f81b51b7eef8e55cc488fdb" - } - } - }, - "2026-06-03-5b2fce600f76": { - "base_version": "0.6.6", - "commit": "5b2fce600f7688059e8ae245da7c6ffc561bb92a", - "built_at": "2026-06-03T12:07:53Z", - "protocol": 12, - "tag": "preview-2026-06-03-5b2fce600f76", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-5b2fce600f76/herdr-linux-x86_64", - "sha256": "c4575cf293f39d72dac0dd6c9618f7e7a46d2b38ebbb7dcbe55d8ebed669866b" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-5b2fce600f76/herdr-linux-aarch64", - "sha256": "20e0b04335f6fb1572eee277b836146c4d4d7cf9d053978fc9e7194ce7ec13df" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-5b2fce600f76/herdr-macos-x86_64", - "sha256": "607c849e721802d3c75e0b6ba677be2baaa2239b5251ab370cb6457231d1ca53" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-5b2fce600f76/herdr-macos-aarch64", - "sha256": "29f3979e08420a6182f9dd0925a15d101dcbbb1eb75948cdf58f927b9f319da8" - } - } - }, - "2026-06-03-fc82cbad2179": { - "base_version": "0.6.6", - "commit": "fc82cbad21791ed58c08905469055eb9357cd350", - "built_at": "2026-06-03T04:35:19Z", - "protocol": 12, - "tag": "preview-2026-06-03-fc82cbad2179", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-fc82cbad2179/herdr-linux-x86_64", - "sha256": "c2291bc05f417329a233d09d769933ccccdc4e1f03e6f2d9a8223464b141728d" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-fc82cbad2179/herdr-linux-aarch64", - "sha256": "bce62864bf3cff6046799acd0e8eb2d6eab546f4be9fe0e37a026704a85db3b2" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-fc82cbad2179/herdr-macos-x86_64", - "sha256": "7990bdc39fa96322b37a497f85bc1963cb40f9f298d400f8da8fe13dac2adaf6" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-03-fc82cbad2179/herdr-macos-aarch64", - "sha256": "c8bcd63323c6daf671022a6872134c6178c153ddd89c4260fbb9b28fe162c18a" - } - } - }, - "2026-06-02-cce3eacc49d2": { - "base_version": "0.6.6", - "commit": "cce3eacc49d281fd087ebf0d43eea3e08038033f", - "built_at": "2026-06-02T20:59:19Z", - "protocol": 12, - "tag": "preview-2026-06-02-cce3eacc49d2", - "assets": { - "linux-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-02-cce3eacc49d2/herdr-linux-x86_64", - "sha256": "c22aa4b2e5fadd6e04910f92bbc125aa749c6a9a9edd281082f07a839e37cbff" - }, - "linux-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-02-cce3eacc49d2/herdr-linux-aarch64", - "sha256": "26a15f394fd27425ab252424fd090913c1ae5cf644f4f3aac0f06c086bdaabb7" - }, - "macos-x86_64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-02-cce3eacc49d2/herdr-macos-x86_64", - "sha256": "c89a97b730e7e3b132a2eca53d49448ec2fb969362e903ce99b5b7b0fbd4d5b1" - }, - "macos-aarch64": { - "url": "https://github.com/herdrdev/herdr/releases/download/preview-2026-06-02-cce3eacc49d2/herdr-macos-aarch64", - "sha256": "0f6c260d9cc65d01c1a58baca5f3ae8150b91f0a16a2ae223b71e76c9dda444f" - } - } - } - } -} 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/docs-preview.integration.test.ts b/website/scripts/docs-preview.integration.test.ts deleted file mode 100644 index f850689c..00000000 --- a/website/scripts/docs-preview.integration.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { afterEach, describe, expect, test } from 'bun:test'; -import { execFileSync } from 'node:child_process'; -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 temporaryDirectories: string[] = []; - -afterEach(async () => { - await Promise.all( - temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true })), - ); -}); - -describe('preview documentation snapshots', () => { - test('snapshots and validates the selected commit exactly', async () => { - const root = await fixture(); - const commit = git(root, ['rev-parse', 'HEAD']).trim(); - await write(root, 'docs/preview/website/stale.mdx', 'stale\n'); - await writeManifest(root, commit); - - runScript(root, ['snapshot', commit]); - runScript(root, ['check']); - - expect(await read(root, 'docs/preview/website/src/content/docs/index.mdx')).toBe( - 'selected preview\n', - ); - await expect(read(root, 'docs/preview/website/stale.mdx')).rejects.toThrow(); - }); - - test('rejects snapshot drift', async () => { - const root = await fixture(); - const commit = git(root, ['rev-parse', 'HEAD']).trim(); - await writeManifest(root, commit); - runScript(root, ['snapshot', commit]); - await write(root, 'docs/preview/website/src/content/docs/index.mdx', 'changed\n'); - - expect(() => runScript(root, ['check'])).toThrow(); - }); -}); - -async function fixture() { - const root = await mkdtemp(join(tmpdir(), 'herdr-preview-docs-')); - temporaryDirectories.push(root); - await write(root, 'docs/next/website/src/content/docs/index.mdx', 'selected preview\n'); - await write(root, 'docs/next/website/src/data/config-reference.json', '{"preview":true}\n'); - git(root, ['init', '-q']); - git(root, ['config', 'user.email', 'test@example.com']); - git(root, ['config', 'user.name', 'Test']); - git(root, ['add', '.']); - git(root, ['commit', '-qm', 'preview fixture']); - return root; -} - -async function writeManifest(root: string, commit: string) { - await write( - root, - 'website/preview.json', - `${JSON.stringify({ - schema_version: 1, - channel: 'preview', - build_id: 'test-build', - commit, - builds: { 'test-build': { commit, tag: 'preview-test-build' } }, - })}\n`, - ); -} - -async function write(root: string, path: string, content: string) { - const destination = resolve(root, path); - await mkdir(resolve(destination, '..'), { recursive: true }); - await writeFile(destination, content, 'utf8'); -} - -async function read(root: string, path: string) { - return readFile(resolve(root, path), 'utf8'); -} - -function git(root: string, args: string[]) { - return execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: 'pipe' }); -} - -function runScript(root: string, args: string[]) { - execFileSync('node', [script, ...args], { - cwd: root, - env: { ...process.env, HERDR_DOCS_REPO_ROOT: root }, - stdio: 'pipe', - }); -} diff --git a/website/scripts/docs-preview.mjs b/website/scripts/docs-preview.mjs deleted file mode 100644 index c0de1fcd..00000000 --- a/website/scripts/docs-preview.mjs +++ /dev/null @@ -1,75 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; -import { - compareGitTree, - createGit, - extractGitTree, - gitPathExists, - resolveCommit, -} from './docs-snapshot.mjs'; - -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 git = createGit(repoRoot); -const sourceRoot = 'docs/next/website'; -const snapshotRoot = resolve(repoRoot, 'docs/preview/website'); -const manifestPath = resolve(repoRoot, 'website/preview.json'); -const fullShaPattern = /^[0-9a-f]{40}$/; - -export async function snapshotPreview(ref) { - const commit = resolveCommit(git, ref); - if (!gitPathExists(git, commit, `${sourceRoot}/src/content/docs`)) { - throw new Error(`${commit} does not contain staged website documentation`); - } - if (!gitPathExists(git, commit, `${sourceRoot}/src/data/config-reference.json`)) { - throw new Error(`${commit} does not contain the staged config reference`); - } - await extractGitTree(git, commit, sourceRoot, snapshotRoot); - process.stdout.write(`snapshotted preview documentation from ${commit}\n`); -} - -export async function checkPreview() { - const manifest = JSON.parse(await readFile(manifestPath, 'utf8')); - if (manifest.schema_version !== 1 || manifest.channel !== 'preview') { - throw new Error(`${manifestPath} has an unsupported schema`); - } - if (typeof manifest.commit !== 'string' || !fullShaPattern.test(manifest.commit)) { - throw new Error(`${manifestPath} must contain a full preview commit SHA`); - } - const build = manifest.builds?.[manifest.build_id]; - if (!build || build.commit !== manifest.commit) { - throw new Error(`${manifestPath} active build does not match its preview commit`); - } - const expectedTag = `preview-${manifest.build_id}`; - if (build.tag !== expectedTag) { - throw new Error(`${manifestPath} active build tag does not match ${expectedTag}`); - } - if (!gitPathExists(git, manifest.commit, `${sourceRoot}/src/content/docs`)) { - throw new Error(`${manifest.commit} does not contain staged website documentation`); - } - if (!gitPathExists(git, manifest.commit, `${sourceRoot}/src/data/config-reference.json`)) { - throw new Error(`${manifest.commit} does not contain the staged config reference`); - } - await compareGitTree(git, manifest.commit, sourceRoot, snapshotRoot); - process.stdout.write(`validated preview documentation snapshot ${manifest.commit}\n`); -} - -async function main() { - const [command, value] = process.argv.slice(2); - if (command === 'snapshot' && value) { - await snapshotPreview(value); - return; - } - if (command === 'check' && !value) { - await checkPreview(); - return; - } - throw new Error('usage: node website/scripts/docs-preview.mjs check | snapshot <commit>'); -} - -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - await main(); -} diff --git a/website/scripts/docs-snapshot.mjs b/website/scripts/docs-snapshot.mjs deleted file mode 100644 index e9eaf92c..00000000 --- a/website/scripts/docs-snapshot.mjs +++ /dev/null @@ -1,116 +0,0 @@ -import { execFileSync } from 'node:child_process'; -import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'; -import { dirname, relative, resolve } from 'node:path'; - -export function createGit(repoRoot) { - return function git(args, options = {}) { - return execFileSync('git', args, { - cwd: repoRoot, - encoding: options.binary ? undefined : 'utf8', - maxBuffer: 64 * 1024 * 1024, - stdio: ['ignore', 'pipe', 'pipe'], - }); - }; -} - -export function resolveCommit(git, ref) { - return git(['rev-parse', `${ref}^{commit}`]).trim(); -} - -export function gitPathExists(git, ref, path) { - try { - git(['cat-file', '-e', `${ref}:${path}`]); - return true; - } catch { - return false; - } -} - -export function gitTreesEqual(git, ref, left, right) { - try { - git(['diff', '--quiet', `${ref}:${left}`, `${ref}:${right}`]); - return true; - } catch { - return false; - } -} - -export function listGitEntries(git, ref, root) { - const output = git(['ls-tree', '-r', '-z', ref, '--', root]); - return output - .split('\0') - .filter(Boolean) - .map((line) => { - const separator = line.indexOf('\t'); - const [mode, type, object] = line.slice(0, separator).split(' '); - return { mode, type, object, path: line.slice(separator + 1) }; - }); -} - -export async function extractGitTree(git, ref, sourceRoot, destinationRoot) { - const entries = listGitEntries(git, ref, sourceRoot); - if (entries.length === 0) throw new Error(`${ref}:${sourceRoot} contains no files`); - - await rm(destinationRoot, { recursive: true, force: true }); - for (const entry of entries) { - assertOrdinaryFile(entry, ref); - const relativePath = relative(sourceRoot, entry.path); - assertRelativePath(relativePath, entry.path); - const destination = resolve(destinationRoot, relativePath); - await mkdir(dirname(destination), { recursive: true }); - await writeFile(destination, git(['cat-file', 'blob', entry.object], { binary: true })); - } -} - -export async function compareGitTree(git, ref, sourceRoot, snapshotRoot) { - const expectedEntries = listGitEntries(git, ref, sourceRoot); - if (expectedEntries.length === 0) throw new Error(`${ref}:${sourceRoot} contains no files`); - - const expected = new Map(); - for (const entry of expectedEntries) { - assertOrdinaryFile(entry, ref); - const relativePath = relative(sourceRoot, entry.path); - assertRelativePath(relativePath, entry.path); - expected.set(relativePath, entry); - } - const actualPaths = await listDocumentationPaths(snapshotRoot); - const expectedPaths = [...expected.keys()].sort(); - if (JSON.stringify(actualPaths) !== JSON.stringify(expectedPaths)) { - throw new Error(`${snapshotRoot} file list differs from ${ref}:${sourceRoot}`); - } - - for (const relativePath of expectedPaths) { - const entry = expected.get(relativePath); - const snapshotPath = resolve(snapshotRoot, relativePath); - const expectedContent = git(['cat-file', 'blob', entry.object], { binary: true }); - if (!(await readFile(snapshotPath)).equals(expectedContent)) { - throw new Error(`${relativePath} differs from ${ref}:${entry.path}`); - } - } -} - -export async function listDocumentationPaths(root) { - const paths = []; - async function walk(directory) { - for (const entry of await readdir(directory, { withFileTypes: true })) { - const path = resolve(directory, entry.name); - if (entry.isDirectory()) await walk(path); - else if (entry.isFile()) paths.push(relative(root, path)); - else throw new Error(`${path} is not an ordinary documentation file`); - } - } - await walk(root); - return paths.sort(); -} - -function assertOrdinaryFile(entry, ref) { - if (entry.type !== 'blob' || entry.mode !== '100644') { - throw new Error(`${ref}:${entry.path} is not an ordinary documentation file`); - } -} - -function assertRelativePath(relativePath, originalPath) { - if (!relativePath || relativePath === '..' || relativePath.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`)) { - throw new Error(`unsafe snapshot path ${originalPath}`); - } -} diff --git a/website/scripts/docs-versions.integration.test.ts b/website/scripts/docs-versions.integration.test.ts deleted file mode 100644 index 2eba45cb..00000000 --- a/website/scripts/docs-versions.integration.test.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { afterEach, describe, expect, test } from 'bun:test'; -import { execFileSync } from 'node:child_process'; -import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises'; -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 temporaryDirectories: string[] = []; - -afterEach(async () => { - 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 () => { - 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, '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'; - await write(root, 'docs/next/website/src/content/docs/index.mdx', nextDocs); - await write(root, 'docs/next/website/src/data/config-reference.json', '{"next":true}\n'); - await write(root, 'docs/next/README.md', 'next readme\n'); - await write(root, 'docs/next/README.zh-CN.md', 'next readme zh-cn\n'); - - git(root, ['init', '-q']); - git(root, ['config', 'user.email', 'test@example.com']); - git(root, ['config', 'user.name', 'Test']); - git(root, ['add', '.']); - git(root, ['commit', '-qm', 'release fixture']); - git(root, ['tag', 'v0.9.0']); - git(root, ['tag', 'v1.0.0']); - - 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); - - const manifest = JSON.parse(await read(root, 'docs/versions/manifest.json')); - expect(manifest.current).toBe('1.0.0'); - expect(manifest.stable_source).toBe('snapshot'); - expect(manifest.versions[0]).toMatchObject({ - version: '1.0.0', - tag: 'v1.0.0', - commit: expect.stringMatching(/^[0-9a-f]{40}$/), - 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'); - 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/data/config-reference.json', - '{"corrected":true}\n', - ); - runScript(root, ['check']); - - await write(root, 'README.md', 'post-release correction\n'); - 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'); - expect(archivedManifest.versions.map(({ version }) => version)).toEqual(['1.0.0', '0.9.0']); - expect(await read(root, 'README.md')).toBe('post-release correction\n'); - runScript(root, ['check']); - - const correctedArchivedDocs = '---\ntitle: Documentation\n---\n\ncorrected archived docs\n'; - await write( - root, - 'docs/versions/0.9.0/website/src/content/docs/index.mdx', - correctedArchivedDocs, - ); - runScript(root, ['publish', 'v0.9.0']); - expect(await read(root, 'docs/versions/0.9.0/website/src/content/docs/index.mdx')).toBe( - correctedArchivedDocs, - ); - - 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( - root, - 'docs/versions/0.9.0/website/src/content/docs/index.mdx', - correctedArchivedDocs, - ); - const linkedPage = resolve(archivedDocsRoot, 'linked.mdx'); - await symlink('index.mdx', linkedPage); - expect(() => runScript(root, ['check'])).toThrow(); - await rm(linkedPage); - runScript(root, ['check']); - - 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); -}); - -async function write(root: string, path: string, content: string) { - const destination = resolve(root, path); - await mkdir(resolve(destination, '..'), { recursive: true }); - await writeFile(destination, content, 'utf8'); -} - -async function read(root: string, path: string) { - return readFile(resolve(root, path), 'utf8'); -} - -function git(root: string, args: string[]) { - return execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: 'pipe' }); -} - -function runScript(root: string, args: string[]) { - execFileSync('node', [script, ...args], { - cwd: root, - env: { ...process.env, HERDR_DOCS_REPO_ROOT: root }, - 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/website/scripts/docs-versions.mjs deleted file mode 100644 index 0923d683..00000000 --- a/website/scripts/docs-versions.mjs +++ /dev/null @@ -1,286 +0,0 @@ -import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; -import { - createGit, - extractGitTree, - gitPathExists, - gitTreesEqual, - listDocumentationPaths, - resolveCommit, -} from './docs-snapshot.mjs'; - -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 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 git = createGit(repoRoot); - -const VERSION_PATTERN = /^v?(\d+\.\d+\.\d+)$/; - -export function normalizeVersion(value) { - const match = VERSION_PATTERN.exec(value); - if (!match) throw new Error(`version must look like 0.7.5 or v0.7.5, got ${value}`); - return match[1]; -} - -export function sortVersionsNewestFirst(versions) { - return [...versions].sort((left, right) => compareVersions(right.version, left.version)); -} - -function compareVersions(left, right) { - const a = left.split('.').map(Number); - const b = right.split('.').map(Number); - for (let index = 0; index < 3; index += 1) { - if (a[index] !== b[index]) return a[index] - b[index]; - } - return 0; -} - -async function readManifest() { - try { - return JSON.parse(await readFile(manifestPath, 'utf8')); - } catch (error) { - if (error.code === 'ENOENT') { - return { schema_version: 1, stable_source: 'legacy', current: null, versions: [] }; - } - throw error; - } -} - -async function writeManifest(manifest) { - manifest.versions = sortVersionsNewestFirst(manifest.versions).map( - ({ version, tag, commit, source }) => ({ - version, - tag, - ...(commit ? { commit } : {}), - source, - }), - ); - await mkdir(dirname(manifestPath), { recursive: true }); - await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8'); -} - -function releaseMetadata(tag) { - const version = normalizeVersion(tag); - const normalizedTag = `v${version}`; - return { version, tag: normalizedTag, commit: resolveCommit(git, normalizedTag) }; -} - -async function snapshotTag(tag, sourceRoot) { - const metadata = { ...releaseMetadata(tag), source: sourceRoot }; - const destination = resolve(versionsDir, metadata.version); - await rm(destination, { recursive: true, force: true }); - await extractGitTree(git, tag, sourceRoot, resolve(destination, 'website/src/content/docs')); - - const referenceSource = sourceRoot.includes('docs/next/') - ? 'docs/next/website/src/data/config-reference.json' - : 'website/src/data/config-reference.json'; - if (gitPathExists(git, tag, referenceSource)) { - const referenceDestination = resolve(destination, 'website/src/data/config-reference.json'); - await mkdir(dirname(referenceDestination), { recursive: true }); - await writeFile(referenceDestination, git(['show', `${tag}:${referenceSource}`], { binary: true })); - } - - return metadata; -} - -export async function backfillVersions() { - const tags = git(['tag', '--list', 'v*', '--sort=v:refname']).split('\n').filter(Boolean); - const manifest = await readManifest(); - const entries = new Map(manifest.versions.map((entry) => [entry.version, entry])); - - for (const tag of tags) { - const version = normalizeVersion(tag); - if (entries.has(version)) continue; - const nextRoot = 'docs/next/website/src/content/docs'; - const legacyRoot = 'website/src/content/docs'; - const hasNext = gitPathExists(git, tag, nextRoot); - const hasLegacy = gitPathExists(git, tag, legacyRoot); - if (!hasNext && !hasLegacy) continue; - const sourceRoot = - hasNext && (!hasLegacy || !gitTreesEqual(git, tag, legacyRoot, nextRoot)) - ? nextRoot - : legacyRoot; - const metadata = await snapshotTag(tag, sourceRoot); - entries.set(metadata.version, metadata); - process.stdout.write(`snapshotted ${tag}\n`); - } - - const current = JSON.parse(await readFile(resolve(repoRoot, 'website/latest.json'), 'utf8')).version; - await writeManifest({ - schema_version: 1, - stable_source: manifest.stable_source ?? 'legacy', - current: normalizeVersion(current), - versions: [...entries.values()], - }); -} - -export async function checkVersions() { - const manifest = await readManifest(); - if ( - manifest.schema_version !== 1 || - typeof manifest.current !== 'string' || - !['legacy', 'snapshot'].includes(manifest.stable_source ?? 'legacy') - ) { - throw new Error(`${manifestPath} has an unsupported schema`); - } - - const latest = JSON.parse(await readFile(resolve(repoRoot, 'website/latest.json'), 'utf8')).version; - if (manifest.current !== normalizeVersion(latest)) { - throw new Error(`docs current version ${manifest.current} does not match website latest ${latest}`); - } - - const expectedOrder = sortVersionsNewestFirst(manifest.versions).map(({ version }) => version); - if (JSON.stringify(manifest.versions.map(({ version }) => version)) !== JSON.stringify(expectedOrder)) { - throw new Error('documentation versions are not sorted newest first'); - } - - const seen = new Set(); - for (const entry of manifest.versions) { - if (seen.has(entry.version)) throw new Error(`duplicate docs version ${entry.version}`); - seen.add(entry.version); - if (normalizeVersion(entry.tag) !== entry.version) { - throw new Error(`docs version ${entry.version} has mismatched tag ${entry.tag}`); - } - const requiresCommit = - entry.source === 'docs/next/website/src/content/docs' || - ((manifest.stable_source ?? 'legacy') === 'snapshot' && entry.version === manifest.current); - if (requiresCommit && !entry.commit) { - throw new Error(`docs version ${entry.version} is missing commit provenance`); - } - if (entry.commit) { - if (!/^[0-9a-f]{40}$/.test(entry.commit)) { - throw new Error(`docs version ${entry.version} has invalid commit ${entry.commit}`); - } - const taggedCommit = resolveCommit(git, entry.tag); - if (taggedCommit !== entry.commit) { - throw new Error( - `docs version ${entry.version} tag ${entry.tag} moved from ${entry.commit} to ${taggedCommit}`, - ); - } - } - if (!['website/src/content/docs', 'docs/next/website/src/content/docs'].includes(entry.source)) { - throw new Error(`docs version ${entry.version} has unsupported source ${entry.source}`); - } - - const versionRoot = resolve(versionsDir, entry.version, 'website'); - const documentationPaths = await listDocumentationPaths( - resolve(versionRoot, 'src/content/docs'), - ); - if (!documentationPaths.includes('index.md') && !documentationPaths.includes('index.mdx')) { - throw new Error(`docs version ${entry.version} has no root index`); - } - - try { - JSON.parse(await readFile(resolve(versionRoot, 'src/data/config-reference.json'), 'utf8')); - } catch (error) { - if (error.code !== 'ENOENT') throw error; - } - } - - if (!seen.has(manifest.current)) { - throw new Error(`current docs version ${manifest.current} has no snapshot`); - } - process.stdout.write(`validated ${manifest.versions.length} documentation versions\n`); -} - -export async function publishVersion(tag) { - const release = releaseMetadata(tag); - if (!gitPathExists(git, tag, 'docs/next/website/src/content/docs')) { - throw new Error(`${tag} does not contain staged website documentation`); - } - - const manifest = await readManifest(); - const existing = manifest.versions.find((entry) => entry.version === release.version); - if (manifest.current === release.version) { - if ((manifest.stable_source ?? 'legacy') === 'legacy') { - process.stdout.write(`documentation ${release.tag} is already published with the legacy stable source\n`); - return; - } - if (!existing?.commit || existing.commit !== release.commit) { - throw new Error(`published documentation ${release.version} has mismatched commit provenance`); - } - process.stdout.write(`documentation ${release.tag} is already published\n`); - return; - } - if (manifest.current && compareVersions(release.version, manifest.current) < 0) { - if (existing) { - if (existing.tag !== release.tag) { - throw new Error(`version ${release.version} is already associated with ${existing.tag}`); - } - if (existing.commit && existing.commit !== release.commit) { - throw new Error(`version ${release.version} has mismatched commit provenance`); - } - process.stdout.write(`documentation ${release.tag} is already archived\n`); - return; - } - const archived = await snapshotTag(tag, 'docs/next/website/src/content/docs'); - const archivedEntries = new Map(manifest.versions.map((entry) => [entry.version, entry])); - archivedEntries.set(archived.version, archived); - await writeManifest({ - ...manifest, - versions: [...archivedEntries.values()], - }); - process.stdout.write( - `archived documentation snapshot ${release.tag} without changing current ${manifest.current}\n`, - ); - return; - } - if (existing) { - throw new Error(`version ${release.version} already has published documentation`); - } - - 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}`; - if (gitPathExists(git, tag, nextReadme)) { - await writeFile(resolve(repoRoot, readme), git(['show', `${tag}:${nextReadme}`], { binary: true })); - } - } - - const entries = new Map(manifest.versions.map((entry) => [entry.version, entry])); - entries.set(metadata.version, metadata); - await writeManifest({ - schema_version: 1, - stable_source: 'snapshot', - current: metadata.version, - versions: [...entries.values()], - }); - process.stdout.write(`published documentation snapshot ${metadata.tag}\n`); -} - -async function main() { - const [command, value] = process.argv.slice(2); - if (command === 'backfill' && !value) { - await backfillVersions(); - return; - } - if (command === 'publish' && value) { - await publishVersion(value); - return; - } - if (command === 'check' && !value) { - await checkVersions(); - return; - } - if (command === 'current' && !value) { - const manifest = await readManifest(); - process.stdout.write(`${manifest.current ?? ''}\n`); - return; - } - throw new Error( - 'usage: node website/scripts/docs-versions.mjs backfill | check | current | publish <tag>', - ); -} - -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - await main(); -} diff --git a/website/scripts/docs-versions.test.ts b/website/scripts/docs-versions.test.ts deleted file mode 100644 index dc450b37..00000000 --- a/website/scripts/docs-versions.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { describe, expect, test } from 'bun:test'; -import { normalizeVersion, sortVersionsNewestFirst } from './docs-versions.mjs'; - -describe('normalizeVersion', () => { - test.each([ - ['0.7.5', '0.7.5'], - ['v0.7.5', '0.7.5'], - ])('normalizes %s', (input, expected) => { - expect(normalizeVersion(input)).toBe(expected); - }); - - test('rejects non-release refs', () => { - expect(() => normalizeVersion('preview-123')).toThrow(); - }); -}); - -describe('sortVersionsNewestFirst', () => { - test('sorts semantic versions numerically', () => { - const versions = [ - { version: '0.6.10' }, - { version: '0.7.2' }, - { version: '0.7.10' }, - { version: '0.5.12' }, - ]; - - expect(sortVersionsNewestFirst(versions).map(({ version }) => version)).toEqual([ - '0.7.10', - '0.7.2', - '0.6.10', - '0.5.12', - ]); - }); -}); 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. - - 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> · 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> · 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> · 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; -} |
