From 482fd58d808e7a0086481108b155039a6c663718 Mon Sep 17 00:00:00 2001 From: David Pine Date: Sun, 8 Mar 2026 16:46:33 -0500 Subject: [PATCH 01/14] docs: rewrite documentation site with Astro Replace the custom Node.js static site generator (build.js + markdown-it) with a modern Astro 5 site using Tailwind CSS v4. Changes: - New Astro project in docs/ with content collections for docs and blog - Modern landing page with hero, feature grid, code example, and CTAs - Responsive sidebar navigation with dark/light theme toggle - All 82 doc pages and 29 blog posts preserved and migrated - Shiki syntax highlighting replaces highlight.js - Internal docs (specs, proposals, audits) moved to docs/_internal/ - Updated GitHub Actions workflow for Astro builds - Updated docs-build.test.ts for new Astro build system (20 tests passing) - Root package.json docs scripts updated (docs:build, docs:dev, docs:preview) Tech stack: Astro 5, Tailwind CSS 4, Shiki, GitHub Pages Build: 114 pages in ~2.5s Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/squad-docs.yml | 8 +- .squad-templates/workflows/squad-docs.yml | 10 +- docs/.gitignore | 3 + docs/README.md | 74 - docs/{ => _internal}/accessibility.md | 0 .../audits/adapter-unsafe-casts-audit.md | 0 docs/{ => _internal}/copy-review-spec.md | 0 .../internal/getting-started-journey.md | 0 .../launch/migration-announcement.md | 0 .../launch/release-notes-v060.md | 0 docs/{ => _internal}/prd-cli-polish.md | 0 docs/{ => _internal}/prd-cli-ui-polish.md | 0 .../proposals/cicd-gitops-prd-cicd-audit.md | 0 .../cicd-gitops-prd-release-audit.md | 0 .../proposals/cicd-gitops-prd.md | 0 .../proposals/fixed-input-box-design.md | 0 .../proposals/reliable-init-flow.md | 0 docs/{ => _internal}/release-checklist.md | 0 docs/{ => _internal}/specs/memory-format.md | 0 .../specs/platform-adapter-prd.md | 122 +- docs/{ => _internal}/specs/streams-prd.md | 276 +- docs/assets/script.js | 55 - docs/assets/squad-logo.png | Bin 117649 -> 0 bytes docs/assets/style.css | 86 - docs/assets/template.html | 27 - docs/astro.config.mjs | 18 + docs/build.js | 365 - docs/cli/installation.md | 322 - docs/cli/shell.md | 516 -- docs/cli/vscode.md | 406 - docs/index.md | 74 - docs/package-lock.json | 6580 +++++++++++++++++ docs/package.json | 18 + docs/sdk/api-reference.md | 804 -- docs/sdk/integration.md | 89 - docs/sdk/tools-and-hooks.md | 95 - docs/src/components/Footer.astro | 53 + docs/src/components/Header.astro | 48 + docs/src/components/Sidebar.astro | 87 + docs/src/components/ThemeToggle.astro | 25 + .../001-wave-0-the-team-that-built-itself.md | 0 .../blog/001a-the-squad-squad-problem.md | 0 .../content}/blog/001b-meet-the-squad.md | 0 .../content}/blog/001c-first-pr-amolchanov.md | 0 .../content}/blog/002-first-community-pr.md | 0 .../content}/blog/003-super-bowl-weekend.md | 0 .../content}/blog/004-v020-release.md | 0 .../content}/blog/005-v030-give-it-a-brain.md | 0 .../blog/006-first-external-deployment.md | 0 .../content}/blog/007-first-video-coverage.md | 0 .../content}/blog/008-v040-release.md | 0 .../content}/blog/009-v040-sprint-progress.md | 0 .../content}/blog/010-v041-patch-release.md | 0 .../011-skills-system-learning-from-work.md | 0 .../content}/blog/012-trending-on-github.md | 0 .../blog/013-the-replatform-begins.md | 0 .../blog/014-wave-1-otel-and-aspire.md | 0 .../blog/015-wave-2-the-repl-moment.md | 0 .../blog/016-wave-3-docs-that-teach.md | 0 .../content}/blog/017-version-alignment.md | 0 .../blog/018-the-adapter-chronicles.md | 0 .../content}/blog/019-shaynes-remote-mode.md | 0 .../{ => src/content}/blog/020-docs-reborn.md | 0 .../content}/blog/021-the-migration.md | 0 .../blog/022-welcome-to-the-new-squad.md | 0 .../blog/023-subsquads-horizontal-scaling.md | 266 +- .../content}/blog/024-v0823-release.md | 0 .../025-squad-goes-enterprise-azure-devops.md | 452 +- .../blog/026-whats-new-ado-comms-subsquads.md | 302 +- docs/src/content/config.ts | 22 + docs/{ => src/content/docs}/community.md | 0 .../content/docs}/concepts/github-workflow.md | 0 .../docs}/concepts/memory-and-knowledge.md | 0 .../content/docs}/concepts/parallel-work.md | 0 .../content/docs}/concepts/portability.md | 0 .../content/docs}/concepts/your-team.md | 0 .../content/docs}/cookbook/recipes.md | 0 .../content/docs}/features/ceremonies.md | 0 .../content/docs}/features/consult-mode.md | 0 .../docs}/features/copilot-coding-agent.md | 0 .../content/docs}/features/directives.md | 0 .../docs}/features/enterprise-platforms.md | 370 +- .../content/docs}/features/export-import.md | 0 .../content/docs}/features/github-issues.md | 0 .../content/docs}/features/gitlab-issues.md | 0 .../docs}/features/human-team-members.md | 0 .../{ => src/content/docs}/features/labels.md | 0 .../content/docs}/features/marketplace.md | 0 docs/{ => src/content/docs}/features/mcp.md | 0 .../{ => src/content/docs}/features/memory.md | 0 .../content/docs}/features/model-selection.md | 0 .../content/docs}/features/notifications.md | 0 .../docs}/features/parallel-execution.md | 0 .../content/docs}/features/plugins.md | 0 .../content/docs}/features/prd-mode.md | 0 .../content/docs}/features/project-boards.md | 0 docs/{ => src/content/docs}/features/ralph.md | 0 .../content/docs}/features/remote-control.md | 652 +- .../content/docs}/features/response-modes.md | 0 .../docs}/features/reviewer-protocol.md | 0 .../content/docs}/features/routing.md | 0 .../{ => src/content/docs}/features/skills.md | 0 .../content/docs}/features/squad-rc.md | 0 .../content/docs}/features/streams.md | 296 +- .../content/docs}/features/team-setup.md | 0 .../docs}/features/upstream-inheritance.md | 0 .../{ => src/content/docs}/features/vscode.md | 0 .../content/docs}/features/worktrees.md | 0 .../docs}/get-started/first-session.md | 0 .../content/docs}/get-started/installation.md | 0 .../content/docs}/get-started/migration.md | 0 docs/{ => src/content/docs}/guide.md | 0 .../content/docs}/guide/contributing.md | 0 .../content/docs}/guide/contributors.md | 0 .../content/docs}/guide/personal-squad.md | 0 .../content/docs}/guide/sample-prompts.md | 0 .../content/docs}/guide/tips-and-tricks.md | 0 .../{ => src/content/docs}/insider-program.md | 0 docs/{ => src/content/docs}/reference/cli.md | 0 .../content/docs}/reference/config.md | 0 docs/{ => src/content/docs}/reference/sdk.md | 0 docs/{ => src/content/docs}/sample-prompts.md | 0 .../docs}/scenarios/aspire-dashboard.md | 0 .../docs}/scenarios/ci-cd-integration.md | 0 .../docs}/scenarios/client-compatibility.md | 0 .../docs}/scenarios/disaster-recovery.md | 0 .../content/docs}/scenarios/existing-repo.md | 0 .../docs}/scenarios/issue-driven-dev.md | 0 .../content/docs}/scenarios/keep-my-squad.md | 0 .../content/docs}/scenarios/large-codebase.md | 0 .../content/docs}/scenarios/mid-project.md | 0 .../content/docs}/scenarios/monorepo.md | 0 .../docs}/scenarios/multi-codespace.md | 254 +- .../docs}/scenarios/multiple-squads.md | 0 .../content/docs}/scenarios/new-project.md | 0 .../content/docs}/scenarios/open-source.md | 0 .../content/docs}/scenarios/private-repos.md | 0 .../docs}/scenarios/release-process.md | 0 .../docs}/scenarios/scaling-workstreams.md | 336 +- .../content/docs}/scenarios/solo-dev.md | 0 .../docs}/scenarios/switching-models.md | 0 .../content/docs}/scenarios/team-of-humans.md | 0 .../docs}/scenarios/team-portability.md | 0 .../docs}/scenarios/team-state-storage.md | 0 .../docs}/scenarios/troubleshooting.md | 0 .../content/docs}/scenarios/upgrading.md | 0 docs/{ => src/content/docs}/sdk-first-mode.md | 0 .../{ => src/content/docs}/tips-and-tricks.md | 0 .../content/docs}/tour-first-session.md | 0 .../content/docs}/tour-github-issues.md | 0 .../content/docs}/tour-gitlab-issues.md | 0 docs/{ => src/content/docs}/whatsnew.md | 0 docs/src/layouts/BaseLayout.astro | 33 + docs/src/layouts/DocsLayout.astro | 29 + docs/src/navigation.ts | 134 + docs/src/pages/404.astro | 21 + docs/src/pages/blog/[...slug].astro | 44 + docs/src/pages/blog/index.astro | 50 + docs/src/pages/docs/[...slug].astro | 22 + docs/src/pages/index.astro | 201 + docs/src/styles/global.css | 151 + docs/template.html | 40 - docs/tsconfig.json | 9 + package-lock.json | 92 +- package.json | 9 +- packages/squad-cli/package.json | 2 +- .../templates/workflows/squad-docs.yml | 10 +- packages/squad-sdk/package.json | 2 +- .../templates/workflows/squad-docs.yml | 10 +- templates/workflows/squad-docs.yml | 10 +- test/docs-build.test.ts | 249 +- 171 files changed, 9347 insertions(+), 4882 deletions(-) create mode 100644 docs/.gitignore delete mode 100644 docs/README.md rename docs/{ => _internal}/accessibility.md (100%) rename docs/{ => _internal}/audits/adapter-unsafe-casts-audit.md (100%) rename docs/{ => _internal}/copy-review-spec.md (100%) rename docs/{ => _internal}/internal/getting-started-journey.md (100%) rename docs/{ => _internal}/launch/migration-announcement.md (100%) rename docs/{ => _internal}/launch/release-notes-v060.md (100%) rename docs/{ => _internal}/prd-cli-polish.md (100%) rename docs/{ => _internal}/prd-cli-ui-polish.md (100%) rename docs/{ => _internal}/proposals/cicd-gitops-prd-cicd-audit.md (100%) rename docs/{ => _internal}/proposals/cicd-gitops-prd-release-audit.md (100%) rename docs/{ => _internal}/proposals/cicd-gitops-prd.md (100%) rename docs/{ => _internal}/proposals/fixed-input-box-design.md (100%) rename docs/{ => _internal}/proposals/reliable-init-flow.md (100%) rename docs/{ => _internal}/release-checklist.md (100%) rename docs/{ => _internal}/specs/memory-format.md (100%) rename docs/{ => _internal}/specs/platform-adapter-prd.md (97%) rename docs/{ => _internal}/specs/streams-prd.md (97%) delete mode 100644 docs/assets/script.js delete mode 100644 docs/assets/squad-logo.png delete mode 100644 docs/assets/style.css delete mode 100644 docs/assets/template.html create mode 100644 docs/astro.config.mjs delete mode 100644 docs/build.js delete mode 100644 docs/cli/installation.md delete mode 100644 docs/cli/shell.md delete mode 100644 docs/cli/vscode.md delete mode 100644 docs/index.md create mode 100644 docs/package-lock.json create mode 100644 docs/package.json delete mode 100644 docs/sdk/api-reference.md delete mode 100644 docs/sdk/integration.md delete mode 100644 docs/sdk/tools-and-hooks.md create mode 100644 docs/src/components/Footer.astro create mode 100644 docs/src/components/Header.astro create mode 100644 docs/src/components/Sidebar.astro create mode 100644 docs/src/components/ThemeToggle.astro rename docs/{ => src/content}/blog/001-wave-0-the-team-that-built-itself.md (100%) rename docs/{ => src/content}/blog/001a-the-squad-squad-problem.md (100%) rename docs/{ => src/content}/blog/001b-meet-the-squad.md (100%) rename docs/{ => src/content}/blog/001c-first-pr-amolchanov.md (100%) rename docs/{ => src/content}/blog/002-first-community-pr.md (100%) rename docs/{ => src/content}/blog/003-super-bowl-weekend.md (100%) rename docs/{ => src/content}/blog/004-v020-release.md (100%) rename docs/{ => src/content}/blog/005-v030-give-it-a-brain.md (100%) rename docs/{ => src/content}/blog/006-first-external-deployment.md (100%) rename docs/{ => src/content}/blog/007-first-video-coverage.md (100%) rename docs/{ => src/content}/blog/008-v040-release.md (100%) rename docs/{ => src/content}/blog/009-v040-sprint-progress.md (100%) rename docs/{ => src/content}/blog/010-v041-patch-release.md (100%) rename docs/{ => src/content}/blog/011-skills-system-learning-from-work.md (100%) rename docs/{ => src/content}/blog/012-trending-on-github.md (100%) rename docs/{ => src/content}/blog/013-the-replatform-begins.md (100%) rename docs/{ => src/content}/blog/014-wave-1-otel-and-aspire.md (100%) rename docs/{ => src/content}/blog/015-wave-2-the-repl-moment.md (100%) rename docs/{ => src/content}/blog/016-wave-3-docs-that-teach.md (100%) rename docs/{ => src/content}/blog/017-version-alignment.md (100%) rename docs/{ => src/content}/blog/018-the-adapter-chronicles.md (100%) rename docs/{ => src/content}/blog/019-shaynes-remote-mode.md (100%) rename docs/{ => src/content}/blog/020-docs-reborn.md (100%) rename docs/{ => src/content}/blog/021-the-migration.md (100%) rename docs/{ => src/content}/blog/022-welcome-to-the-new-squad.md (100%) rename docs/{ => src/content}/blog/023-subsquads-horizontal-scaling.md (97%) rename docs/{ => src/content}/blog/024-v0823-release.md (100%) rename docs/{ => src/content}/blog/025-squad-goes-enterprise-azure-devops.md (97%) rename docs/{ => src/content}/blog/026-whats-new-ado-comms-subsquads.md (97%) create mode 100644 docs/src/content/config.ts rename docs/{ => src/content/docs}/community.md (100%) rename docs/{ => src/content/docs}/concepts/github-workflow.md (100%) rename docs/{ => src/content/docs}/concepts/memory-and-knowledge.md (100%) rename docs/{ => src/content/docs}/concepts/parallel-work.md (100%) rename docs/{ => src/content/docs}/concepts/portability.md (100%) rename docs/{ => src/content/docs}/concepts/your-team.md (100%) rename docs/{ => src/content/docs}/cookbook/recipes.md (100%) rename docs/{ => src/content/docs}/features/ceremonies.md (100%) rename docs/{ => src/content/docs}/features/consult-mode.md (100%) rename docs/{ => src/content/docs}/features/copilot-coding-agent.md (100%) rename docs/{ => src/content/docs}/features/directives.md (100%) rename docs/{ => src/content/docs}/features/enterprise-platforms.md (97%) rename docs/{ => src/content/docs}/features/export-import.md (100%) rename docs/{ => src/content/docs}/features/github-issues.md (100%) rename docs/{ => src/content/docs}/features/gitlab-issues.md (100%) rename docs/{ => src/content/docs}/features/human-team-members.md (100%) rename docs/{ => src/content/docs}/features/labels.md (100%) rename docs/{ => src/content/docs}/features/marketplace.md (100%) rename docs/{ => src/content/docs}/features/mcp.md (100%) rename docs/{ => src/content/docs}/features/memory.md (100%) rename docs/{ => src/content/docs}/features/model-selection.md (100%) rename docs/{ => src/content/docs}/features/notifications.md (100%) rename docs/{ => src/content/docs}/features/parallel-execution.md (100%) rename docs/{ => src/content/docs}/features/plugins.md (100%) rename docs/{ => src/content/docs}/features/prd-mode.md (100%) rename docs/{ => src/content/docs}/features/project-boards.md (100%) rename docs/{ => src/content/docs}/features/ralph.md (100%) rename docs/{ => src/content/docs}/features/remote-control.md (95%) rename docs/{ => src/content/docs}/features/response-modes.md (100%) rename docs/{ => src/content/docs}/features/reviewer-protocol.md (100%) rename docs/{ => src/content/docs}/features/routing.md (100%) rename docs/{ => src/content/docs}/features/skills.md (100%) rename docs/{ => src/content/docs}/features/squad-rc.md (100%) rename docs/{ => src/content/docs}/features/streams.md (97%) rename docs/{ => src/content/docs}/features/team-setup.md (100%) rename docs/{ => src/content/docs}/features/upstream-inheritance.md (100%) rename docs/{ => src/content/docs}/features/vscode.md (100%) rename docs/{ => src/content/docs}/features/worktrees.md (100%) rename docs/{ => src/content/docs}/get-started/first-session.md (100%) rename docs/{ => src/content/docs}/get-started/installation.md (100%) rename docs/{ => src/content/docs}/get-started/migration.md (100%) rename docs/{ => src/content/docs}/guide.md (100%) rename docs/{ => src/content/docs}/guide/contributing.md (100%) rename docs/{ => src/content/docs}/guide/contributors.md (100%) rename docs/{ => src/content/docs}/guide/personal-squad.md (100%) rename docs/{ => src/content/docs}/guide/sample-prompts.md (100%) rename docs/{ => src/content/docs}/guide/tips-and-tricks.md (100%) rename docs/{ => src/content/docs}/insider-program.md (100%) rename docs/{ => src/content/docs}/reference/cli.md (100%) rename docs/{ => src/content/docs}/reference/config.md (100%) rename docs/{ => src/content/docs}/reference/sdk.md (100%) rename docs/{ => src/content/docs}/sample-prompts.md (100%) rename docs/{ => src/content/docs}/scenarios/aspire-dashboard.md (100%) rename docs/{ => src/content/docs}/scenarios/ci-cd-integration.md (100%) rename docs/{ => src/content/docs}/scenarios/client-compatibility.md (100%) rename docs/{ => src/content/docs}/scenarios/disaster-recovery.md (100%) rename docs/{ => src/content/docs}/scenarios/existing-repo.md (100%) rename docs/{ => src/content/docs}/scenarios/issue-driven-dev.md (100%) rename docs/{ => src/content/docs}/scenarios/keep-my-squad.md (100%) rename docs/{ => src/content/docs}/scenarios/large-codebase.md (100%) rename docs/{ => src/content/docs}/scenarios/mid-project.md (100%) rename docs/{ => src/content/docs}/scenarios/monorepo.md (100%) rename docs/{ => src/content/docs}/scenarios/multi-codespace.md (96%) rename docs/{ => src/content/docs}/scenarios/multiple-squads.md (100%) rename docs/{ => src/content/docs}/scenarios/new-project.md (100%) rename docs/{ => src/content/docs}/scenarios/open-source.md (100%) rename docs/{ => src/content/docs}/scenarios/private-repos.md (100%) rename docs/{ => src/content/docs}/scenarios/release-process.md (100%) rename docs/{ => src/content/docs}/scenarios/scaling-workstreams.md (96%) rename docs/{ => src/content/docs}/scenarios/solo-dev.md (100%) rename docs/{ => src/content/docs}/scenarios/switching-models.md (100%) rename docs/{ => src/content/docs}/scenarios/team-of-humans.md (100%) rename docs/{ => src/content/docs}/scenarios/team-portability.md (100%) rename docs/{ => src/content/docs}/scenarios/team-state-storage.md (100%) rename docs/{ => src/content/docs}/scenarios/troubleshooting.md (100%) rename docs/{ => src/content/docs}/scenarios/upgrading.md (100%) rename docs/{ => src/content/docs}/sdk-first-mode.md (100%) rename docs/{ => src/content/docs}/tips-and-tricks.md (100%) rename docs/{ => src/content/docs}/tour-first-session.md (100%) rename docs/{ => src/content/docs}/tour-github-issues.md (100%) rename docs/{ => src/content/docs}/tour-gitlab-issues.md (100%) rename docs/{ => src/content/docs}/whatsnew.md (100%) create mode 100644 docs/src/layouts/BaseLayout.astro create mode 100644 docs/src/layouts/DocsLayout.astro create mode 100644 docs/src/navigation.ts create mode 100644 docs/src/pages/404.astro create mode 100644 docs/src/pages/blog/[...slug].astro create mode 100644 docs/src/pages/blog/index.astro create mode 100644 docs/src/pages/docs/[...slug].astro create mode 100644 docs/src/pages/index.astro create mode 100644 docs/src/styles/global.css delete mode 100644 docs/template.html create mode 100644 docs/tsconfig.json diff --git a/.github/workflows/squad-docs.yml b/.github/workflows/squad-docs.yml index b799c8ab9..3014002ba 100644 --- a/.github/workflows/squad-docs.yml +++ b/.github/workflows/squad-docs.yml @@ -27,11 +27,13 @@ jobs: with: node-version: '22' - - name: Install build dependencies - run: npm install --no-save markdown-it markdown-it-anchor + - name: Install docs dependencies + working-directory: docs + run: npm ci - name: Build docs site - run: node docs/build.js + working-directory: docs + run: npx astro build - name: Upload Pages artifact uses: actions/upload-pages-artifact@v3 diff --git a/.squad-templates/workflows/squad-docs.yml b/.squad-templates/workflows/squad-docs.yml index 307d502c5..bb4e44469 100644 --- a/.squad-templates/workflows/squad-docs.yml +++ b/.squad-templates/workflows/squad-docs.yml @@ -27,16 +27,18 @@ jobs: with: node-version: '22' - - name: Install build dependencies - run: npm install --no-save markdown-it markdown-it-anchor + - name: Install docs dependencies + working-directory: docs + run: npm ci - name: Build docs site - run: node docs/build.js --out _site --base /squad + working-directory: docs + run: npx astro build - name: Upload Pages artifact uses: actions/upload-pages-artifact@v3 with: - path: _site + path: docs/dist deploy: needs: build diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..ddce69b68 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +.astro/ diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index c1b2eb5c0..000000000 --- a/docs/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# Squad Documentation - -Public-facing documentation for Squad. GitHub Pages ready. - -## Guides - -- [Product Guide](guide.md) — Complete reference for all Squad features -- [Sample Prompts](sample-prompts.md) — Ready-to-use prompts showing what Squad can do - -## Feature Reference - -### Core -- [Team Setup](features/team-setup.md) — Init mode, first session, team creation -- [Work Routing](features/routing.md) — How work gets assigned to agents -- [Parallel Execution](features/parallel-execution.md) — Background vs sync, fan-out -- [Response Modes](features/response-modes.md) — Tiered response speed/depth -- [Memory System](features/memory.md) — How agents learn and remember -- [Directives](features/directives.md) — Capturing team rules and preferences -- [Reviewer Protocol](features/reviewer-protocol.md) — Rejection lockout and revision routing - -### Workflow -- [GitHub Issues Mode](features/github-issues.md) — GitHub issue-driven development -- [GitLab Issues Mode](features/gitlab-issues.md) — 🧪 *Experimental* — GitLab issue-driven development -- [PRD Mode](features/prd-mode.md) — Product requirements decomposition -- [Labels & Triage](features/labels.md) — go:/release:/type:/priority: taxonomy -- [Ralph — Work Monitor](features/ralph.md) — Autonomous backlog processing -- [Project Boards](features/project-boards.md) — GitHub Projects V2 integration - -### Team -- [Human Team Members](features/human-team-members.md) — Mixed AI/human teams -- [@copilot Coding Agent](features/copilot-coding-agent.md) — Autonomous issue agent -- [Skills System](features/skills.md) — Earned knowledge with confidence lifecycle -- [Ceremonies](features/ceremonies.md) — Team meetings and rituals -- [Notifications](features/notifications.md) — Ping via Teams/MCP - -### Infrastructure -- [Per-Agent Model Selection](features/model-selection.md) — Cost-first model routing -- [Git Worktrees](features/worktrees.md) — Multi-branch team state -- [Export & Import](features/export-import.md) — Portable team snapshots - -## Walkthroughs - -- [First Session](tour-first-session.md) — Your first time using Squad -- [GitHub Issues](tour-github-issues.md) — GitHub issue-driven development walkthrough -- [GitLab Issues](tour-gitlab-issues.md) — 🧪 *Experimental* — GitLab issue-driven development walkthrough - -## Scenarios - -### Getting Started -- [Starting a New Project](scenarios/new-project.md) — Greenfield setup -- [Adding to an Existing Repo](scenarios/existing-repo.md) — Drop Squad into existing code -- [Mid-Project Onboarding](scenarios/mid-project.md) — Adding Squad halfway through -- [Upgrading Squad](scenarios/upgrading.md) — Update to the latest version - -### Team Management -- [Solo Developer](scenarios/solo-dev.md) — Is Squad overkill for one person? -- [Mixed Human + AI Team](scenarios/team-of-humans.md) — Humans and agents working together -- [Keeping Your Squad](scenarios/keep-my-squad.md) — Persistence across projects -- [Combining Old Squads](scenarios/multiple-squads.md) — Cherry-picking from multiple teams - -### Project Types -- [Large Codebases](scenarios/large-codebase.md) — Will Squad choke on a big repo? -- [Monorepos](scenarios/monorepo.md) — Multiple services, one squad -- [Open Source Projects](scenarios/open-source.md) — Triage, contributors, community - -### Operations -- [Client Compatibility Matrix](scenarios/client-compatibility.md) — What works on CLI, VS Code, JetBrains, GitHub.com -- [Issue-Driven Development](scenarios/issue-driven-dev.md) — End-to-end issue workflow -- [CI/CD Integration](scenarios/ci-cd-integration.md) — Squad + GitHub Actions -- [Moving a Team](scenarios/team-portability.md) — Export and import between repos -- [Team State Storage](scenarios/team-state-storage.md) — Gitignore, submodules, branches, and more -- [Model Selection Strategies](scenarios/switching-models.md) — Budget vs quality tradeoffs -- [Privacy & Security](scenarios/private-repos.md) — What stays private -- [Disaster Recovery](scenarios/disaster-recovery.md) — When things go wrong diff --git a/docs/accessibility.md b/docs/_internal/accessibility.md similarity index 100% rename from docs/accessibility.md rename to docs/_internal/accessibility.md diff --git a/docs/audits/adapter-unsafe-casts-audit.md b/docs/_internal/audits/adapter-unsafe-casts-audit.md similarity index 100% rename from docs/audits/adapter-unsafe-casts-audit.md rename to docs/_internal/audits/adapter-unsafe-casts-audit.md diff --git a/docs/copy-review-spec.md b/docs/_internal/copy-review-spec.md similarity index 100% rename from docs/copy-review-spec.md rename to docs/_internal/copy-review-spec.md diff --git a/docs/internal/getting-started-journey.md b/docs/_internal/internal/getting-started-journey.md similarity index 100% rename from docs/internal/getting-started-journey.md rename to docs/_internal/internal/getting-started-journey.md diff --git a/docs/launch/migration-announcement.md b/docs/_internal/launch/migration-announcement.md similarity index 100% rename from docs/launch/migration-announcement.md rename to docs/_internal/launch/migration-announcement.md diff --git a/docs/launch/release-notes-v060.md b/docs/_internal/launch/release-notes-v060.md similarity index 100% rename from docs/launch/release-notes-v060.md rename to docs/_internal/launch/release-notes-v060.md diff --git a/docs/prd-cli-polish.md b/docs/_internal/prd-cli-polish.md similarity index 100% rename from docs/prd-cli-polish.md rename to docs/_internal/prd-cli-polish.md diff --git a/docs/prd-cli-ui-polish.md b/docs/_internal/prd-cli-ui-polish.md similarity index 100% rename from docs/prd-cli-ui-polish.md rename to docs/_internal/prd-cli-ui-polish.md diff --git a/docs/proposals/cicd-gitops-prd-cicd-audit.md b/docs/_internal/proposals/cicd-gitops-prd-cicd-audit.md similarity index 100% rename from docs/proposals/cicd-gitops-prd-cicd-audit.md rename to docs/_internal/proposals/cicd-gitops-prd-cicd-audit.md diff --git a/docs/proposals/cicd-gitops-prd-release-audit.md b/docs/_internal/proposals/cicd-gitops-prd-release-audit.md similarity index 100% rename from docs/proposals/cicd-gitops-prd-release-audit.md rename to docs/_internal/proposals/cicd-gitops-prd-release-audit.md diff --git a/docs/proposals/cicd-gitops-prd.md b/docs/_internal/proposals/cicd-gitops-prd.md similarity index 100% rename from docs/proposals/cicd-gitops-prd.md rename to docs/_internal/proposals/cicd-gitops-prd.md diff --git a/docs/proposals/fixed-input-box-design.md b/docs/_internal/proposals/fixed-input-box-design.md similarity index 100% rename from docs/proposals/fixed-input-box-design.md rename to docs/_internal/proposals/fixed-input-box-design.md diff --git a/docs/proposals/reliable-init-flow.md b/docs/_internal/proposals/reliable-init-flow.md similarity index 100% rename from docs/proposals/reliable-init-flow.md rename to docs/_internal/proposals/reliable-init-flow.md diff --git a/docs/release-checklist.md b/docs/_internal/release-checklist.md similarity index 100% rename from docs/release-checklist.md rename to docs/_internal/release-checklist.md diff --git a/docs/specs/memory-format.md b/docs/_internal/specs/memory-format.md similarity index 100% rename from docs/specs/memory-format.md rename to docs/_internal/specs/memory-format.md diff --git a/docs/specs/platform-adapter-prd.md b/docs/_internal/specs/platform-adapter-prd.md similarity index 97% rename from docs/specs/platform-adapter-prd.md rename to docs/_internal/specs/platform-adapter-prd.md index e892501bd..be8123113 100644 --- a/docs/specs/platform-adapter-prd.md +++ b/docs/_internal/specs/platform-adapter-prd.md @@ -1,61 +1,61 @@ -# Platform Adapter — Design Spec - -## Overview - -The Platform Adapter abstraction allows Squad to work with multiple source code hosting platforms (GitHub, Azure DevOps) through a unified interface. This enables Ralph and the coordinator to use the same triage/assignment logic regardless of the underlying platform. - -## Design Decisions - -### 1. Interface-based abstraction - -We use a TypeScript interface (`PlatformAdapter`) rather than an abstract class. This keeps the contract pure and allows each adapter to manage its own dependencies independently. - -### 2. CLI-based implementations - -Both adapters wrap CLI tools (`gh` for GitHub, `az` for ADO) rather than using REST APIs directly. This: -- Leverages existing authentication (users are already logged into `gh`/`az`) -- Avoids managing OAuth tokens, PATs, or refresh flows -- Matches how Squad already interacts with GitHub - -### 3. Auto-detection from git remote - -Platform detection reads the `origin` remote URL. This is zero-config — users don't need to specify which platform they're on. - -### 4. Graceful failure - -If the required CLI is not installed, the adapter throws a descriptive error with installation instructions rather than a cryptic exec failure. - -## Mapping Table - -| Concept | GitHub | Azure DevOps | -|---|---|---| -| Work item | Issue | Work Item | -| Work item query | `gh issue list --label X` | WIQL via `az boards query` | -| Work item tags | Labels | Tags (`;`-separated) | -| Pull request list | `gh pr list` | `az repos pr list` | -| Pull request create | `gh pr create` | `az repos pr create` | -| Pull request merge | `gh pr merge` | `az repos pr update --status completed` | -| Branch create | `git checkout -b` | `git checkout -b` | -| Review status | `reviewDecision` field | `vote` field on reviewers | -| Authentication | `gh auth login` | `az login` | - -## Module Structure - -``` -packages/squad-sdk/src/platform/ -├── types.ts # PlatformType, WorkItem, PullRequest, PlatformAdapter -├── detect.ts # detectPlatform, parseGitHubRemote, parseAzureDevOpsRemote -├── github.ts # GitHubAdapter -├── azure-devops.ts # AzureDevOpsAdapter -├── ralph-commands.ts # getRalphScanCommands -└── index.ts # Factory + barrel exports -``` - -## Future Work - -- **GitLab adapter** — Same interface, wrapping `glab` CLI -- **Bitbucket adapter** — Same interface, wrapping Bitbucket APIs -- **REST API fallback** — Direct API calls when CLI tools aren't available -- **Token-based auth** — Support PAT/token auth for CI environments -- **Pipelines abstraction** — Normalize GitHub Actions and Azure Pipelines -- **Board view** — Normalize GitHub Projects and ADO Boards +# Platform Adapter — Design Spec + +## Overview + +The Platform Adapter abstraction allows Squad to work with multiple source code hosting platforms (GitHub, Azure DevOps) through a unified interface. This enables Ralph and the coordinator to use the same triage/assignment logic regardless of the underlying platform. + +## Design Decisions + +### 1. Interface-based abstraction + +We use a TypeScript interface (`PlatformAdapter`) rather than an abstract class. This keeps the contract pure and allows each adapter to manage its own dependencies independently. + +### 2. CLI-based implementations + +Both adapters wrap CLI tools (`gh` for GitHub, `az` for ADO) rather than using REST APIs directly. This: +- Leverages existing authentication (users are already logged into `gh`/`az`) +- Avoids managing OAuth tokens, PATs, or refresh flows +- Matches how Squad already interacts with GitHub + +### 3. Auto-detection from git remote + +Platform detection reads the `origin` remote URL. This is zero-config — users don't need to specify which platform they're on. + +### 4. Graceful failure + +If the required CLI is not installed, the adapter throws a descriptive error with installation instructions rather than a cryptic exec failure. + +## Mapping Table + +| Concept | GitHub | Azure DevOps | +|---|---|---| +| Work item | Issue | Work Item | +| Work item query | `gh issue list --label X` | WIQL via `az boards query` | +| Work item tags | Labels | Tags (`;`-separated) | +| Pull request list | `gh pr list` | `az repos pr list` | +| Pull request create | `gh pr create` | `az repos pr create` | +| Pull request merge | `gh pr merge` | `az repos pr update --status completed` | +| Branch create | `git checkout -b` | `git checkout -b` | +| Review status | `reviewDecision` field | `vote` field on reviewers | +| Authentication | `gh auth login` | `az login` | + +## Module Structure + +``` +packages/squad-sdk/src/platform/ +├── types.ts # PlatformType, WorkItem, PullRequest, PlatformAdapter +├── detect.ts # detectPlatform, parseGitHubRemote, parseAzureDevOpsRemote +├── github.ts # GitHubAdapter +├── azure-devops.ts # AzureDevOpsAdapter +├── ralph-commands.ts # getRalphScanCommands +└── index.ts # Factory + barrel exports +``` + +## Future Work + +- **GitLab adapter** — Same interface, wrapping `glab` CLI +- **Bitbucket adapter** — Same interface, wrapping Bitbucket APIs +- **REST API fallback** — Direct API calls when CLI tools aren't available +- **Token-based auth** — Support PAT/token auth for CI environments +- **Pipelines abstraction** — Normalize GitHub Actions and Azure Pipelines +- **Board view** — Normalize GitHub Projects and ADO Boards diff --git a/docs/specs/streams-prd.md b/docs/_internal/specs/streams-prd.md similarity index 97% rename from docs/specs/streams-prd.md rename to docs/_internal/specs/streams-prd.md index 6a9dc9fba..d7467aee5 100644 --- a/docs/specs/streams-prd.md +++ b/docs/_internal/specs/streams-prd.md @@ -1,138 +1,138 @@ -# SubSquads PRD — Product Requirements Document - -> Scaling Squad across multiple Codespaces via labeled SubSquads. - -## Problem Statement - -Squad was designed for a single agent team per repository. In practice, larger projects hit scaling limits: - -1. **Rate limits**: A single Codespace hitting model API rate limits blocks the entire team -2. **Triage overload**: Ralph picks up all open issues, even those outside the current focus area -3. **File contention**: Multiple agents editing the same files causes merge conflicts -4. **Context window saturation**: Large repos exceed practical context limits for a single coordinator - -### Validated by Experiment - -We tested this with a 3-Codespace setup building a multiplayer Tetris game. Each Codespace ran Squad independently, manually filtering by GitHub labels. The results showed 3x throughput for independent SubSquads, validating the approach. However, the manual coordination was error-prone and needed to be automated. - -## Requirements - -### Must Have (P0) - -- [ ] **SubSquad Definition**: Define SubSquads in `.squad/streams.json` with name, label filter, folder scope, and workflow -- [ ] **SubSquad Resolution**: Automatically detect active SubSquad from env var, file, or config -- [ ] **Label Filtering**: Ralph only triages issues matching the SubSquad's label -- [ ] **Folder Scoping**: Agents restrict modifications to SubSquad's folder scope -- [ ] **CLI Management**: `squad subsquads list|status|activate` commands -- [ ] **Init Integration**: `squad init` optionally generates SubSquads config -- [ ] **Agent Template**: squad.agent.md includes SubSquad awareness instructions - -### Should Have (P1) - -- [ ] **SubSquad Status Dashboard**: Show PR/branch activity per SubSquad -- [ ] **Conflict Detection**: Warn when SubSquads overlap on file paths -- [ ] **Auto-labeling**: Suggest labels for new issues based on file paths - -### Could Have (P2) - -- [ ] **Meta-coordinator**: A coordinator that orchestrates across SubSquads -- [ ] **Cross-SubSquad dependencies**: Track and resolve inter-SubSquad blockers -- [ ] **SubSquad metrics**: Throughput, cycle time, merge conflict rate per SubSquad - -## Design Decisions - -### 1. GitHub Labels as the Partition Key - -**Decision**: Use GitHub labels (e.g., `team:ui`) to partition work across SubSquads. - -**Rationale**: Labels are a first-class GitHub concept. They're visible in the UI, queryable via API, and already used by Squad for agent assignment. No new infrastructure needed. - -**Alternatives considered**: -- Custom metadata in issue body — fragile, not queryable -- Separate repositories — too heavy, loses monorepo benefits -- Branch-based partitioning — branches are for code, not work items - -### 2. File-Based SubSquad Activation - -**Decision**: Use `.squad-workstream` file (gitignored) for local activation, `SQUAD_TEAM` env var for Codespaces. - -**Rationale**: The file is simple and doesn't require environment configuration. The env var is ideal for Codespaces where the environment is defined in `devcontainer.json`. Both are easy to understand and debug. - -### 3. Resolution Priority (Env > File > Config) - -**Decision**: Env var overrides file, which overrides config auto-select. - -**Rationale**: In Codespaces, the env var is the most reliable signal. On local machines, the file is convenient. Config auto-select handles the simple case of a single SubSquad. - -### 4. Synthesized Definitions for Unknown SubSquads - -**Decision**: When `SQUAD_TEAM` or `.squad-workstream` specifies a SubSquad name not in the config, synthesize a minimal definition with `labelFilter: "team:{name}"`. - -**Rationale**: Fail-open is better than fail-closed. Users should be able to set `SQUAD_TEAM=my-team` without needing to update `streams.json` first. The convention of `team:{name}` is predictable and consistent. - -## Design Clarifications - -### Overlapping Folder Scope - -**Multiple SubSquads MAY work on the same folders.** `folderScope` is an advisory guideline, not a hard lock. Reasons: - -- **Shared packages**: In a monorepo, `packages/shared/` might be touched by all SubSquads. Preventing access would break legitimate work. -- **Interface contracts**: Backend and Frontend SubSquads both need to update shared type definitions. -- **Branch isolation handles it**: Since each issue gets its own branch (`squad/{issue}-{slug}`), two SubSquads editing the same file won't conflict until merge time — and Git resolves non-overlapping changes automatically. - -**When it breaks**: Semantic conflicts — two SubSquads make incompatible API changes to the same file. This happened in the Tetris experiment where Backend restructured `game-engine/index.ts` exports while UI added color constants to the same file. Git merged cleanly but the result needed manual reconciliation. - -**Mitigation (v2)**: Conflict detection — warn when two SubSquads have open PRs touching the same file. Surface this in `squad subsquads status`. - -### Single-Machine Multi-SubSquad - -**One machine can serve multiple SubSquads to save costs.** Instead of 1 Codespace per SubSquad: - -```bash -# Sequential switching -squad subsquads activate ui-team # Ralph works team:ui issues -# ... switch when done ... -squad subsquads activate backend-team # now works team:backend issues -``` - -**v2: Round-robin mode** — Ralph cycles through SubSquads automatically: -```json -{ - "workstreams": [...], - "mode": "round-robin", - "issuesPerWorkstream": 3 -} -``` - -| Approach | Cost | Speed | Isolation | -|----------|------|-------|-----------| -| 1 Codespace per SubSquad | N× | Fastest (true parallel) | Best | -| 1 machine, manual switch | 1× | Serial | Good | -| 1 machine, round-robin | 1× | Interleaved | Okay — branches isolate, context switches add overhead | - -Branch-per-issue ensures no file conflicts regardless of approach — the "SubSquad" only determines which issues Ralph picks up. - -## Future Work - -### Meta-Coordinator - -A "coordinator of coordinators" that: -- Monitors all SubSquads for cross-cutting concerns -- Detects when one SubSquad's work blocks another -- Suggests label assignments for ambiguous issues -- Produces a unified status dashboard - -### Cross-SubSquad Dependencies - -Track when a SubSquad needs work from another SubSquad: -- Automated detection via import graphs -- Cross-SubSquad issue linking -- Priority escalation for blocking dependencies - -### SubSquad Templates - -Pre-built SubSquad configurations for common architectures: -- **Frontend/Backend** — 2 SubSquads for web apps -- **Monorepo** — 1 SubSquad per package -- **Microservices** — 1 SubSquad per service -- **Feature teams** — dynamic SubSquads per feature area +# SubSquads PRD — Product Requirements Document + +> Scaling Squad across multiple Codespaces via labeled SubSquads. + +## Problem Statement + +Squad was designed for a single agent team per repository. In practice, larger projects hit scaling limits: + +1. **Rate limits**: A single Codespace hitting model API rate limits blocks the entire team +2. **Triage overload**: Ralph picks up all open issues, even those outside the current focus area +3. **File contention**: Multiple agents editing the same files causes merge conflicts +4. **Context window saturation**: Large repos exceed practical context limits for a single coordinator + +### Validated by Experiment + +We tested this with a 3-Codespace setup building a multiplayer Tetris game. Each Codespace ran Squad independently, manually filtering by GitHub labels. The results showed 3x throughput for independent SubSquads, validating the approach. However, the manual coordination was error-prone and needed to be automated. + +## Requirements + +### Must Have (P0) + +- [ ] **SubSquad Definition**: Define SubSquads in `.squad/streams.json` with name, label filter, folder scope, and workflow +- [ ] **SubSquad Resolution**: Automatically detect active SubSquad from env var, file, or config +- [ ] **Label Filtering**: Ralph only triages issues matching the SubSquad's label +- [ ] **Folder Scoping**: Agents restrict modifications to SubSquad's folder scope +- [ ] **CLI Management**: `squad subsquads list|status|activate` commands +- [ ] **Init Integration**: `squad init` optionally generates SubSquads config +- [ ] **Agent Template**: squad.agent.md includes SubSquad awareness instructions + +### Should Have (P1) + +- [ ] **SubSquad Status Dashboard**: Show PR/branch activity per SubSquad +- [ ] **Conflict Detection**: Warn when SubSquads overlap on file paths +- [ ] **Auto-labeling**: Suggest labels for new issues based on file paths + +### Could Have (P2) + +- [ ] **Meta-coordinator**: A coordinator that orchestrates across SubSquads +- [ ] **Cross-SubSquad dependencies**: Track and resolve inter-SubSquad blockers +- [ ] **SubSquad metrics**: Throughput, cycle time, merge conflict rate per SubSquad + +## Design Decisions + +### 1. GitHub Labels as the Partition Key + +**Decision**: Use GitHub labels (e.g., `team:ui`) to partition work across SubSquads. + +**Rationale**: Labels are a first-class GitHub concept. They're visible in the UI, queryable via API, and already used by Squad for agent assignment. No new infrastructure needed. + +**Alternatives considered**: +- Custom metadata in issue body — fragile, not queryable +- Separate repositories — too heavy, loses monorepo benefits +- Branch-based partitioning — branches are for code, not work items + +### 2. File-Based SubSquad Activation + +**Decision**: Use `.squad-workstream` file (gitignored) for local activation, `SQUAD_TEAM` env var for Codespaces. + +**Rationale**: The file is simple and doesn't require environment configuration. The env var is ideal for Codespaces where the environment is defined in `devcontainer.json`. Both are easy to understand and debug. + +### 3. Resolution Priority (Env > File > Config) + +**Decision**: Env var overrides file, which overrides config auto-select. + +**Rationale**: In Codespaces, the env var is the most reliable signal. On local machines, the file is convenient. Config auto-select handles the simple case of a single SubSquad. + +### 4. Synthesized Definitions for Unknown SubSquads + +**Decision**: When `SQUAD_TEAM` or `.squad-workstream` specifies a SubSquad name not in the config, synthesize a minimal definition with `labelFilter: "team:{name}"`. + +**Rationale**: Fail-open is better than fail-closed. Users should be able to set `SQUAD_TEAM=my-team` without needing to update `streams.json` first. The convention of `team:{name}` is predictable and consistent. + +## Design Clarifications + +### Overlapping Folder Scope + +**Multiple SubSquads MAY work on the same folders.** `folderScope` is an advisory guideline, not a hard lock. Reasons: + +- **Shared packages**: In a monorepo, `packages/shared/` might be touched by all SubSquads. Preventing access would break legitimate work. +- **Interface contracts**: Backend and Frontend SubSquads both need to update shared type definitions. +- **Branch isolation handles it**: Since each issue gets its own branch (`squad/{issue}-{slug}`), two SubSquads editing the same file won't conflict until merge time — and Git resolves non-overlapping changes automatically. + +**When it breaks**: Semantic conflicts — two SubSquads make incompatible API changes to the same file. This happened in the Tetris experiment where Backend restructured `game-engine/index.ts` exports while UI added color constants to the same file. Git merged cleanly but the result needed manual reconciliation. + +**Mitigation (v2)**: Conflict detection — warn when two SubSquads have open PRs touching the same file. Surface this in `squad subsquads status`. + +### Single-Machine Multi-SubSquad + +**One machine can serve multiple SubSquads to save costs.** Instead of 1 Codespace per SubSquad: + +```bash +# Sequential switching +squad subsquads activate ui-team # Ralph works team:ui issues +# ... switch when done ... +squad subsquads activate backend-team # now works team:backend issues +``` + +**v2: Round-robin mode** — Ralph cycles through SubSquads automatically: +```json +{ + "workstreams": [...], + "mode": "round-robin", + "issuesPerWorkstream": 3 +} +``` + +| Approach | Cost | Speed | Isolation | +|----------|------|-------|-----------| +| 1 Codespace per SubSquad | N× | Fastest (true parallel) | Best | +| 1 machine, manual switch | 1× | Serial | Good | +| 1 machine, round-robin | 1× | Interleaved | Okay — branches isolate, context switches add overhead | + +Branch-per-issue ensures no file conflicts regardless of approach — the "SubSquad" only determines which issues Ralph picks up. + +## Future Work + +### Meta-Coordinator + +A "coordinator of coordinators" that: +- Monitors all SubSquads for cross-cutting concerns +- Detects when one SubSquad's work blocks another +- Suggests label assignments for ambiguous issues +- Produces a unified status dashboard + +### Cross-SubSquad Dependencies + +Track when a SubSquad needs work from another SubSquad: +- Automated detection via import graphs +- Cross-SubSquad issue linking +- Priority escalation for blocking dependencies + +### SubSquad Templates + +Pre-built SubSquad configurations for common architectures: +- **Frontend/Backend** — 2 SubSquads for web apps +- **Monorepo** — 1 SubSquad per package +- **Microservices** — 1 SubSquad per service +- **Feature teams** — dynamic SubSquads per feature area diff --git a/docs/assets/script.js b/docs/assets/script.js deleted file mode 100644 index 04cfccc78..000000000 --- a/docs/assets/script.js +++ /dev/null @@ -1,55 +0,0 @@ -(function(){ - var saved=localStorage.getItem("squad-theme"); - if(saved) document.documentElement.setAttribute("data-theme",saved); - updateThemeBtn(); -})(); -function toggleTheme(){ - var html=document.documentElement; - var c=html.getAttribute("data-theme"); - var n=c==="dark"?"light":c==="light"?"auto":"dark"; - html.setAttribute("data-theme",n); - localStorage.setItem("squad-theme",n); - updateThemeBtn(); - // Re-render mermaid diagrams with updated theme - if(typeof mermaid!=="undefined"){ - mermaid.initialize({startOnLoad:false,theme:n==="light"?"default":"dark"}); - mermaid.run(); - } -} -function updateThemeBtn(){ - var t=document.documentElement.getAttribute("data-theme"); - var b=document.getElementById("theme-btn"); - if(!b) return; - b.textContent=t==="dark"?"\u2600\uFE0F":t==="light"?"\uD83C\uDF19":"\uD83D\uDCBB"; - syncHljsTheme(); -} -function syncHljsTheme(){ - var t=document.documentElement.getAttribute("data-theme"); - var dark=t==="dark"||(t!=="light"&&window.matchMedia("(prefers-color-scheme:dark)").matches); - var ld=document.getElementById("hljs-light"); - var dd=document.getElementById("hljs-dark"); - if(ld) ld.disabled=dark; - if(dd) dd.disabled=!dark; -} -function toggleSidebar(){ - document.getElementById("sidebar").classList.toggle("open"); -} -(function(){ - var input=document.getElementById("search"); - var results=document.getElementById("search-results"); - function esc(s){ return s.replace(/&/g,"&").replace(//g,">"); } - input.addEventListener("input",function(){ - var q=this.value.toLowerCase().trim(); - if(q.length<2){ results.classList.remove("visible"); return; } - var matches=searchIndex.filter(function(e){ - return e.title.toLowerCase().indexOf(q)!==-1 || e.preview.toLowerCase().indexOf(q)!==-1; - }).slice(0,10); - if(!matches.length){ results.innerHTML='
No results
'; } - else { results.innerHTML=matches.map(function(m){ - return ''+esc(m.title)+'
'+esc(m.preview.substring(0,100))+'
'; - }).join(""); } - results.classList.add("visible"); - }); - input.addEventListener("blur",function(){ setTimeout(function(){ results.classList.remove("visible"); },200); }); - input.addEventListener("keydown",function(e){ if(e.key==="Escape"){ this.value=""; results.classList.remove("visible"); } }); -})(); diff --git a/docs/assets/squad-logo.png b/docs/assets/squad-logo.png deleted file mode 100644 index 47ad53a5ec30b4cff6fe3e5647dfc2ff707338c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117649 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

5vTZsTCZZY(#g4_n`2G5QSG>nux{_5m*~(Xq^gM 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

h($0^_|G*aOg?8mADiD z&3plY!X-5*bn%UVudZK}aPEVDu%bCrlSEY=MH3McWuBX*jaToo#qKYv+Kd#B9CGSb zb&*d-N!RFN2*yd}G?)l-@}zYyJpR{J+hx%T&7W8-Qle@S8`xu8s~`|5@U}PXGI5!q z<>xDpsQowx?-fE|!Dw+>iv)oz&I9Pey>|7~b*CLZ zx80?Gzv|PQzhmd>`cCD|Kzi8!{pQ%7_rB#S-D0y>`FaiZ$dea*>-59_US0ci-usR( zB;D%1=$@LCAbd)%T?J5wmW7{ha>*(8Rc+S>W*>CQmI>qyuy&9gXjiqz?PGBG*SBV0 zx6IG@>FjjbnG5BgC?*vgmkLb&cH5vuF=-47Xq2oC+q%|PgjI;o#qoy?pNv+p+PdT7!Gg3^} z>;zZ(2?Al1iV=u7vDm9BE!b^$_Ro3Na+%-H|Mj;3yOy#21)!l_We0}9)cDGCryRC* z)oyKI*NaYG+!CB<0HG?P?axIej;jmAcqB*Ox&P6dS8V~{?Pq+10Py9{zw1wKaPX4E z3Br;gOE%kh*V-?Sxa#ol{${D0fllH5hn@M#&Hr@cKN_!n#c49Grx$sPZo!fwz2=|G zz1B`@j(=|&u(Jp(gdhTqF(m*X#hcCVr(f>tJYT6(-lM=cQEeyB5gYWADDRs4;@2ns z^Rj1kh}q!c6CarG2ahHc0)bf=p64Jjr6#PIyzbFSyRA^f@vOZ*t7qqzbMRl6$bP4}K=LwSE%tBJJ= zy58{<d&Gu;#6zL>Nl@@bj@ac%&Nfu@2citlcE(Fx0~^>{w=_dPz-NL~8Ict^(# zIs||UXhDP1#eJ}qs`}sL;*)Az?;Ii5d z8;pV?){b}RjrBL}va+lbjIMc_@J93y8`Z$*qio z`&2@yQ-l;j%iswQ8MD8uX(Cnz+EA0;8_Er) zzAgF4n{PPmyT5y9)n-lc(L+AJ#SxcYdv1N_9lwJto9LUli8%4WR2TKn>iOLz$5d^q zOtT4x^#s`_MtelbSZoPV1*l%|*b~0>zg4@nh3$H$z9u2I7XqNg35dbK5Mrwu!Rvu$!`*kU+Km(hx+zRW6fQ|&!HcLvB0vUz zX?6W-;%11zK!_&obBrLEjc;Mu9W0$d$2)XNvL&*tOEjerMv@wJ1_C5mR9(M17~fT& zE3ml&A`}Hg9iUFk3>HGqSBAH`Bg8-VI%8hAthh5L2caLRlBu?Dd!!1wFiIyR0Jbxr(rS=#>(G6% zYFB0O$X}do149oZb!tYMFEP|NV0q#;XzaGrufA}>Uw`%451qbg)ovvD+|SN`L)S4M z`b*eg>KpUCW%)oes5+r48ks}a6HlCZ>TkZW%v1GW4*0@`lQjL5nt(zM7jXh4Lom7o zEs-;~yX5rM)`r^YWQzUU4`k9P?Xe34AeJcTYCo&mJR7#Z{LK3YeEAJJhbROc+uLLP zEFs>bf#gF~yODy1R9q$yp)XtUgdB4OFq6ls>sJR>w4Pw_P?y5Y$NM@yTWi@yJ9T__ zPsclS-x}K1iPYmo?nP7}X$mK{q`O{QdQbH#WY;?{Zicd%t2!hu5d{PxpgqK_{Ni$| zdRH|Y*Sq)1fOSMcC-KIl2&D+V$Z&Y`Z!J7(;6%*(2FPv?6N{BVA8$K6Ml!9(jct#|i8 zoQjHAX+*m97Vk_y{ic5%@rNr%Jh%Q{pyxAx{L}v?+irbD*4@1^%ffsx5vS713j_x# zpO}65J#U-#-KuSsZQaDf8{*byqERfN?MOrvDyju|{dxJE6{_BTKJw_nr%rUDQN}Dr z+1k@-gapNhaL09zKl~rca4W;TLkquM2p)tcDsj|mtY8o!L1u~D_r?Q`StG-SL`gM^ zqMQ^FO<)!nAn?Gy!-K1nP|k$~nt9PAB}s<7Ns61`x+Zj-2v3!ccj)5Mp4fYC0NW!y zNhoAV62fZFsQ|#4(P0-L5q!x|v|wc+s(?6IWdj0MlpdG9L*o><*dMO0y^V)@3yTN5 zUnP^NzTxNGK*7x-5DZUZ6U57gKqA=p$$d{)BQ*q_z=oHebaNBo#{?k;#_+KKQ7pwW zt#$QkZMl-L-}>lVe_vnN_eWDje_x-eI+mpuAz2O%F^F3y-DayF9ChVCfA*PaUmTI# z`bWO><5#Zpms_vtdf^K`B}w8~luXh@8jU(#l0cF~xOmADz2MJBpSzq+lZOvIW7jTm z9}`i?Fl3x$WkJ2rFD~=bK6L5V|4aF7ZDG8)107`3DD|pO?F`L=QWP!ncl%xc?dSaY zyzc6+F3jnFC~@*4+CvH8M1=rr#@-E+?%k?(BZ397P{Kk1b%}^N0!kGiwJ;)wrh2V@ zXPP!<#l97VOEQRa0vgJpCF@q#cN!h<&;jYOIG>j45(0!0VDQcC{!2$BhYkSZ5`zdd zNk!CAog-t&eMCRQhxa^s3ngC%wxi$LzB5B?{V4?(Zg$zp4_ED0hA&_K-Leef*A^Ag zfZ-5bEWkA{O?&D{mn{DBm%n$yZPnMPG6{Ne2GpRSwFROeDxy&_p+A%t zZhXl}OI1Ew8>oqU3qpt~2w3~37J)#5V$ncr=yz3{m1Q2nAG~N^jFD&*nu*#qkPy&A zS?=|^S};q+IT2Bqc>=L$$wCRUVnouKoPPcMU}Yav(QaRp*gXVj*2t>sJB<-_M$eW_ z0ClzcPH9>Lp`z-TrgZ=U3&p^nR$_eK>vnqQ%3c@&08|z9Wz3^PAfh7^3To4p)%SFz zkHv5x%uL7ts4&n_(4JGCtx7)Fe~|$Tg-9^a@a7Ng_K}Xi&{r4RTyf@% zA=v+!0Bk#`w(K@2v=o9#%#Q!&n@?D#w)yd&efLA!x8&?vPdAb@fhdrq4oRZ$MImBF zUlg9bJsa0vvduZi|LxWvpK|y&S7}b~e~$XcwmZk!9j(kv4diG`qv z(tD$J)sglO{DTL){%h6Os50}A6W`td_m*K-6~geS4T?AoE*TsIPp{goP0Ts?v~3f^ z?$M)a9C>aKqZvgI%wMzd<)=PawOd)XKL3PAN}pdDuTx{}y`-rs1VSZtyLPW5M|}8H zECCb|m$V-@5>++SA&ii(dK~aTC`1JSA?ip`8U;z#wN-U}r!gWQ(#kResKM1<Vfy{Qh75F8lg!FK8Of7<_>F0Ej|G!~w469ES#)?CMm*0HGA`3wYC)PXX#xgHEEO9r}hCpPGd(nn6iw zk_Z74C1~MU?^yqQ+i&ceThFmS-}38ceQ`+CAp}UVvWUI#QI2-RS{W|f=d%+;lb5Sg z#99IagD1@k0JIpcd&Qr=vdp0vD?=0E#|8mtak@kMxFxDgoO9i2?afu2wTV|>eb&4I z-}+LB-${(U$BYO`qlAE7(a+y<;E_u$Hu}GxT`pg<3kTd?4;-6-fuuU;5R6C?2UVqW z4nu#C~VbEOd6 z@Frzq)C$}VpP-sFxaemciRq!Xw`%7?gOT5$L{l<1&SpcM(9{TV; zN3GKE?`UJ=$A0tOT<~WyRtydgzYr0j(7HV)Y?QlWt9HYD@_qaAyz{P=FMsTiCwhyd{E zADw^5dS`w5df8y=n~PxP3(rt`RS^(GQ4|P1usPHOj9}u_<;C>$Z9hM?`kGZ9d(+7~ z)=WNzwkR=Z605i4UXV$GA^4NGy7aWwIg6p=ne6KOIml*l^Vcp@i=P)rq9o7Tz#Y#gF);jQ4wP>i+OuMMLP*mUX&z>=9w91{hJca+CF@Y&CJeJuds)rPrPQ z!Q~8k*#oG5@()*kySDT8e@rIyZWLOD6+@U<9u?eqx1x{hj6Qs3L%ZE4ki5GKU3bi%0tPcjZ~9&DFG2->?CRD&`FS% z7YwUqlMVp6;PwE8KdSD8Y;bNDIEbu|bT4MiGn=K?RG_ zB#9ay7Dz=%&{p`8 z_HM$^quH9NjO`#^aOtTxG+{rcI4Be%?aa3bBypN#S-P%k9EYQqy#f6G*@w-~|9RWt z;ypwaMd7X0Y@y6cvFKQ7W|F9rMpqXA$k2j?1gyKZ)n>C zPrctqPx=0CFTMJvYkIcY?2{rQ5&}gi^{$2_X(ld7grqE4vP4Nr>?|W8D(|2^b+`kdN;r+X;dtIM5r>etumt64=Un{zWwyIL-2G=emk)9cs0u70|@jK`Or(M>pO`NaYQRik~MlE4x|vGOq`>03Wl(x zE?A~A)vAYtI*2+EnnDwSH#iY{*$9Xp{9yM_Oeih95+TG~n*exffCJ%yJF7OUl8r7p z@nNraHQLpmvG+P422p_ovdip4&RA-Wcx_=;-aMmF%!$+K5L>k39v@1vUen#5y!+&L zRPCyK`?K#kkMo!OTs0AOD$QmSeM^=gZ?-@HP8=*4idK$Vt%jbSZdmC#w0MbeT<`W> zuif>kBQE^wnIGEy=*h>wZ(jnyr+#+n=O<3v+YJDo=X-kV$sS$0g@zP(aN!C z{sMwTqtO5WrfCA#Rd=<%zB%1D+_>DH`g0Ec!nkovPD&a3@#7S4iO<8hFVG>D=WKBP ziC0!_*EV{QyfFdBk+k7xyMY3lQ4{25=TvQ0C39MXPZ&596Lu!fx!8Oe^G4`JvQyP& zbs~t(@Xng;>?@gE6Xn0+8^=7*}1bysl^BxWsG&lCX9ZGyVq% zBtlVKQMFmslx9DtDu6hMBud~4ATR;OXJ%`4aU1|_f5n-PFZQjkn>q}iv>;IwmY^gC zj6-_b^@pCY+#QT86Y%L$Cmnk|YVr zyg;kjWbj^+EJHm}=;Jd_J@q@MEmz;*HF?kHGvn42F*C+|Xxz~V32l<|W|z$qs&;D~ zo9^j?;cc+?mYD4_a{@3p6U^x^^VQm$|Fvx1{mvzKnhyU40t*2mN(Vt*bTe$c>}b*| zg&~n71>>#)2&I^Lh`JH{C4hO4-?SL!n=Y-v$^r->Cej6PNo{;}eJ9b;4n1?}Hd$7K zlSB~3280%1t!7^nb4N5>=bSU=98^W($=Kr5HS^C|y=g^omTaFu>ku`FSUZ0obNea- zE%?W)HmjQHEdElI`Gdo`dkbDbgQ&n!P}AgHf8Xc$W#(_!2F_db=(qYqaf`&BMv|bY z#<|uCt3x*53SFP8+Ew|=cMg9%SupPuGN9FJ(nyxRgi9P81nL}yhMFkLGDb~kDDwgq z0-T7MnYXUmmf7Z;9&hVT-UkY64)lk?!9fW{fqbZiqLoW?Xoy8#U~pi7^+p|OJww*0 z(K)3gA~I{vKWguN({j}Z|GEEBFYL|IPpg2jlARK3{uQDEieRwF&)nwXQy#6_u5HZN z{xz?tIk!zbmJf%M6=;X}Sn7TG3NeT$Wd`Sv-`qS2* zU9W1l+7K6@?P~=9ToMmT!Gq>UEQekI1*{wt5x81|5PPbH&_WpT{`_Y{$2#NYrIEM^6X{U6ZWeOsFZJ)#BE30TWy0enb{8N?X zRx~Lhgn4Mu8jRQJ-^s;AD7l;Xg0cL@!?GP^w zR_4#T2mQH2DO=5`q~sJnZ=xJr0)&wX6m+Rumoz{X!xb7dKtwUfFdIMn-_@SS2Y`W4 zTR_ zx88kZ-G@O}uch&7%@S|V(=HVY+uJFsl2cJBx%j7*8 zdmDjx)`U>tM5Lr)Q7Dez<&v{TG*#A#+_=Z*)~$&8iNxVCgeph$ z00)+LCR0U=1{iYHKMRUX-3PQpGU??RN z1sFWk46*_zm*>hkulrPY;?n3ZRE)?bZRN=hncpY++qxn_A|4~vO}MkcH%)*yDDcN^NCw(a~GYJ zHfm6(qUvPb4b~Tupb_Rhh6V?aW*Lj3kfJEyoMV!tpb=@3B1uyQ3os)R=ip1vf&Kw$ z4z(n2wO}Ej)~HF(xE_#{T2HSeix%H7<*n0}EBtcuw8I(`=}ylG6^N1X$--D{0W;H9 z@Rx3K$w?PhZP!LNYK%KD(PS#xM%dw$WHF(*xR5x!sP+`nA zkPrqlh%fK0+N@3r`d|M0X(O>KJr?tr115DRx>k=>9cH`B&b)1j&;K_{!U#o`92U(W zsb<FIxY+bI*OwpCs*ZMQRJ*8IPC#Ae;RD4Ap#k~9HnsMYHT-XlqzlzEOc%i!84 z@4>-A2oTlY%&>65!Wh&fND_^%2D4fQUzD^!6rdz!G0?i^ABP>g0vpzk*VjLyTaq0G zai)m0wTGyHh)8hgTTlNzin7zfAzD(Px}&OROU#Xt<21i(W3 zW-*9LSADbHHmI)e6gt+Sx61MbM)V5FBuOc%?c!=(2$9vEFRqeO1|bSnjhk3eB(*NU zrOoQvRgGuzVn;NFgP9uV%>gtCs(yaiTIF)D%VM!FuL#5w?MHVUEv8D**sRr1eb;%r zzPn?0u_MWCEWSDvaeqS(YLMLw9cvoO9^v=|YypwxGNyQHFrU z3l~~FOTot;`_})S^yz4rOq;dLE z+}B7HX%t%d;9SaT?Ln`y`K71MZTa$#F>yvAVh$aMm5U19{?+SlwR_cWZDiVIXDwW8 z`SE3x1B(xEr!nX*0yUzW?y$!WI(?bB${(NeXZiAxAGlE;n{h_HmPoBpN3C8HUlho) z48eQW8#UCs>PXZfOH(9i0t*2a0tWi~Is1uOND_y>#eFD?f(!=d9DJUm$a6U7IDWl# zoPT28T|9K}FI9hs|6qP+TEaNEcPXU? ziM8#+ec!PcoX9QwrfRdgF(+3-1maYZBr4Sj2vJ3*t}&r^+=!e=ZSlgUiu5H$Q5edi z1v7&r34(8pXqwfQ+;e{@TZ<(GsB@r|pcz4P4EczB9xFq~I`qUP<3t3i4rT!&?P4FA zA6#_T$QDQdD3;9qDT|>wX|1M7nu;W;q$kslV$lS{KE*YAh*c1ZIJWSx;{W zXXABCub$@t0RRU2`;jE6IG0eeRM{#}Tz}J%X9IoJ-=WHk#?GJUfqMf;FN{^v z0NN=9Ab@Bg9J}9*-(6C*T^qS$?<1zvU3PGE;wB;z%M9Y}gVMsxCw%{Ef1Xt755-Jt zkNpi%W1F$f5DY}EEc}RU&L3(`pDX3i)k&IyaN?3oMWAB-{={s#g_*08zP|nzLRmr; zjJ^2~1!x{lUB|ZOcC14$z2C+xAXtgSCE}6K#f82lZYSUTePf8q=K^RnE>XsW8T^($GpXC?y7nfL#`ebOf{t-gPi+YdQzqe(71(zVM22r%{#D-=SgN>l9* z>t1rwYP~;36PtEVe0?Ia2|}Q%Yj*)4&V^71lIOnUva?2f^RpoMheTwC1rLVMp7<8) zARLHZV56$d>Y}k==I7IadHWtzAl;j<_BlrHmkaJb&>#PzE~)TbtfFI zc}OxK>)N!szEkK_hwcEpc({%l5PI+7M3E)QE!U555Be~-J@Tg;-hJz@rgh!==N)#r z?)&@x^`>8~_FmBg$FJL+xn%R<)<*-x;t5?s@M!vCjW~1w)(ZLW;_T+9E+f(mBA_Fu zj?cOe`A?Izmkq8s^}ZIuSr&_*2ndw1K}ggwa|tFV_0#X#|AgfVSA6O458d5*__5D- zcXfd@3uQpjDuhO4wHiU7)ykuOgDSlb5P<~mS>y%04+y1)#GZB0G=(;5N!s7{NY{x! zII;SE&%}mooL-}BKouLFyD5wn_Yl$2$=n&`z*r&N(`I)nP@DHh`aH^!lF@Y*7P86BC$yJ-x#ceaLUwrSK=Y6VY(exd924-#Z z;5`=|`tZ!_N4#cgF;J?=KM)GgN|-M|UjP;$n!c=4eP>7hQd0oul61U^!YqIwlC&lQ zLkPthRhjxUU|0CZ7JX@iHWk!l%hV;^1f#G)tk3{KHArZd#Tpww+0XKip0*flhmsi; zuLwW_;fQxvZPsRP_jCTwo83f03BrPp8&(n&SWS`*Hnilds@*g3mACHw>ts>?`Rbf& z4Gcb2U2Y*zoieMXFbnYBW3ay;t!9fBLJZG?P*o|55?QTI6H(1u=)UW|BTv2Q=gXa> z_T-_b9^9?&JrdhCV<{XE$N7rFoT9I6o%NDS&sqa|5uM2`Z}`F%U9R@(D6h(R+7peH z)1Ia)+qKYjJqwSxgO}1YUE_?jK)nC&sGe)|odhy#28o=2d?_ zl2|$Lhzg-eMu9*zrNnt2>umtUoK=U>kq&+8xEFMbNG($lZq_sHd*h>kn@gAdgn zpLM)8QiQ~zEInF7P2{Z{G(&e!4=fnE8g=yc_DEM(L+Xv1bai)8C`hst-IFFr)@(kJ ze&i?1RjmVn&9n86s+rrm{Y9%lv^`P;Af*Hc%hG@P@@u|ZR&Cc}wC3EqhucmWf{=iS z8YnDa{qu{~1r?hSWyt*8AYw5WBr-fjQAFuXdeYKfRkeA(qrih^mdCFufmwisf-sp< zTDEOMrx@54KKB0zp|60ExkYA+%a8DT)$VR-*-jOPu6I z4zUu+z4xE+rFp+t?jVr6rk(Jr@!Iv-r)FPK$Y6k(&_ToePQ00=NGE&Ta~SDgMx)ovsiaC(mjA0{l;ct|XmGz(-1n3&dgsM<&lf{PT-JzF87$DqhKL)nLcwQ4M>=$Kt}8kPP()~EvC=SYm zt{0yCM6NuZnt;IsG$;W;ASzG_#!)}>@ZLx7TeW>A#-DTPVcnD&!KovOJTD|k6ATRu z!a0X5%TTm(ihx6dgD_GwacuPVh|ZjQ-svBF%a5zCS>@Q*ysxog+W1P1tXrJZmgqJGB}cyZyvnv0pR%}B7IO@Un~tX% zWF<~i6xph3^L(d&&Ru=N&=L#qWlIz)LV^lNz0p-&-wAZ2L$4=|4H0L46AW$XKZTeL z)ap-5^gPe$u20w^6W1FHG8E!e+S8CgTCs%1atoM7f<7z%=miC0KNbOPKMV|NhHjU> zqiVCZGx?84|D>t>U6cokJ--S8%tTa~Ax)+v-Dh6#hEMlaZL1vjqf;MmJo?yiU9}oq znuv-blpeKO2FAQPvMd7#_@b0rEd@m+oxgYvess|h)z^C_J~QP-hxI^T$zVprHhNV- z`)*Y4)GxN;$d6q0e*j9m#$)10^aDMAb`xF!A7H^UPmS zwObREf}3M4i~t}54cgwZ6=kvOrMn-t+%(Yhi5&1|=#1ejP;76!Gn%5sH9T+y^>4NdpDXWwJDsM@XVERgcpBGLH-ghm()ND@#0LkJB`cHDLR z2FF$Ho{3Z5y3a50_!B=0B0>f;5+MZ1vJ?cFW+_TvBCFL{f>0XDo9;OLjNhN}Q1!K{ zJTUF#m-f&d9rqprK*UIxz$ijdhZe&3H@@(Mzf^5U69-=Ll~@a~3fV||_Dlk|j5!rh zXb2VnQ9v9D!5_E1?6i)EIu_(#Nrkob<=X>VU?ggWaWCqfIO-hwi(jzEN^jC~paAV= z3n7+$x*9}N7=bd_GL;?I6dmc%A$XCBz(R;)&_x&+5XylEs!N~GbfvY;06?6^eq~5o zT}DxW3toEp86z%2u{4GlehZE10Hpv%S{xY4G}t=prS-AmxC&cbaN(>Ll};V$1JX1Rl2WhNDGEAG#LayC zCue`*eZQ!_#(%N@N3+Q;`BshSCC%aptSCA{GYF^!?7r#NTA`f(+D6SKA9$KdgNi7e zD9M1})c0Fh?OGNq${_s{5HtyBY*;{){8K?9Zk#XtE2=h~&OHxZ^PDzm)*5&S^uyz) zNPwXjLh$)|SqIKV??i|0yvcfHS)yG52GS%1k6>;@^?cVT+wGN_53eGlrZQ9ns!@?E za#h7*jWTnv@8Ux2Q7DA+RBp9h3L&V8dk1#fuj6ijHO>0-uKf0p@J}&g*`7IS?E!X1 z%RFln>CV1l-(!~grx=u~w82 z9lm)*#7Tkh&o|D#vttSf@8QtxrTK>`0s`CchvKQ+gjNFPqaGB{ zn37DWSJ$s;I?kc*u-?v%GWaa!V95|lQ3YJg?Q}%WcqDjWi`}{t<7OfP5~iXg4G_Wz zh%Y;;+W!@QK6_yxE>Lx##ots^5gXZPiO5SIUH|1HH(PnMaNS=*ANaXkY#{a{LTDk5 zS&esq)eJjrm(-Ry;N(-Ee-{DZ)K9KR5vWR`_}>jKKH;LO?HIuLuI{%uV-Fw}M;Hwc ztR+o|B?ANJ-+c4$+XDD&o;P0hwLAxA$7e4LAdG~7Fbhy}jik+9yWPR^+U*Wr>CpLe zA<1fY3((RSHX}qS>P(VsopQqZ+f~=EX*$lKo9gDN%O(Q?D_e>X1Z62&@Mj22dDv1d}h%ue$Y9FfFi~($N z!LfJdf-_^vLTDm{h{WM+q5{JtaUYw$?=kyVZJ!C5_Ubb+d*QX>QV9lYmBB)=pxq7V zV>5pIrO&?W%BsyXAX^0Y)moBHFa_hWBucyj&Ll~taC-lvLrYGn8jb;6Iqm44n&E8- z0r4}__>CgEcTZWoNbUDkyETmmuZ%97Q~{i5REbhyPZ2a`#V8tlCyN1sKG|H+-NG{G7sqQ=_1s zq&j!*ZM6e-U!hR@V+Wk{zAnx7rV7P50SvT2#0EPFB4JTz9siOm&Ke7~KLgunWA~cL zi$#QSs@hZk2t}okaQO~bo;kg0x29>8<%8{Hu@Hj5SUEufYLH3WcTeg_g|yX0@x*ll z0(d71D_evwpe_L|0Ks>h{Ar=lqB@uH7ZT-7ryMg6P7#Pa>RM!_7H;qV_Ty-DuTAttsqQj8*P|&?^iV&1Nfi6 ze7m*K@*@k-Yy1G)fltG*JIKgwUpjv3$yM8D;;jGs{6opZk9@JGw{BF^o=_~FaMg_; zIu2N_1HNgWqt>5XYn+@)6!E165)clLNEK*{{-+yXcw)z$Fgu0R+q=?sF523k9W4mW zBsgFow0>E&=>!&(ttTiLa4PY)Cm}BGE)DD@wIi#$R~NHO8&oT96(?|M2A9>KE>TGm zh=h(iV0M&4-(~YX_Ert!CxTeqc$d-fJef#RY$6b^Y@g2XVU(SHKOIr4SGm z0U0{(bUw@g@H?+qV1PzdP*5a}dQ||K(|1;F#)xcs@kv+rS^0h9-_aO|puL$R%&Zsg z3rC*unH8ETy>YGktQxV2Ss+AU@i(CeAgbb> z&Umc3aD}F_t&QBY_ZK(m$r`VZ5vuqz(RNZ=1SRd>nF9;|TD9v07SzJsh4+ug{zM@( ziduQ|bgEgGb1$meJkOyYT=?b0{5&wIXeusAk*Soc%=Ac8tizUE^Ps3fDD;csz$71OrH;It*F(`EGyxPDe%?r(OPypyaRZY?Y`?U_24E^QeH4C`0i5<~uI; z_H>4VKZj6=5u!p>70?)9RI-tYzO`yIM&#vJoV9pfXdWKGQexCIp7P@Hm?SKNzHpQA zlU68V^|7xWHupX6opxUJ=g-7tha5A03bHRb14M*T^RNB>go#Vh0?(On?hzdsF76Z> z$ljqbvW8g6C2*o}&ba{0o16Flx@yx&h?DEv|4V3u#>^S=qCgqAb1d!-73-~7ENXWnqrAkeC==>$5~p|8!1Q@4|WJ%xFTeJ-&NAE2trta+BN zaSiun@vp&Ie=jWDMHPi8j07Q~;>2iZq}j9|?)J`()I#nAwz%w+Yx-a(GwN=}!}+jh zAR#2WnY{1OeU3YzYWrMx8M;rcL6=EPDy&L5YQBL!r2EhpWCaqiWYlEGhHb0|=*aFqTCv3{mHh0GnUE*XLHa80?JQ zKeo)%?-;9=F^ArP^tiNFor7~x7^LmVNdiUii(fk9^p22oDgrZV8Qf%7Kl94{R*k;)eFvYk zS1;Ws5sXCCYH#QA0SL`0mW2G29WFV&qn**3rjFYF38g2HW+cr#Vy6nEuwYFIE0p?J zlMFJ<64BBJlR!f-V;MY*fen}TuA7cqVS$-r{_?%$o_;%(&DMYEQ=5@Z*L$gKy8ezG zzd0Fm=$(gn%Ilp0N|8jI1ezEDr;38S3wL+^fSLgb=Xsh3q0S|u?deS*Af;EO9$d8< z<3F%I7DstyzXb}762)c!I0aI%%;|R9B$E!W8a`XDKj^5Q4JAFhCZbwP2`35*ZBZbh zsA}o#(hV*+?nhPIG5(XDdiDmRkNZ~JFd6s`Y+i8DviyizI0gK(g8>}S%1f5qjk66bffjQ@2Qw| z1Y-`p!}!bYhu2cbw!w%%gQr1MMTBBeJ*=JI>TGVt(A`G6P2!`C5I~(1NX*OC)xEfC zGsb_i@kJ-yJP7+TUEB=CznmDM zx;Pb%5Wth7;>1DFo1{~!HqR$$)(vB0`jfW|#jZo(u{pQ;$7bJFK*R{<1oNt0CotyF zJB)R^d)AlWdprXGg;OQl;tnBk917*A2zefQ$yb^~@c)1a3`AQtlu<8BkcivpUk4sH zzG^qde{$u(BVWlK{@iXO5-_yoR{=oSpk(VY`Nl8zIcB9!4EOGH^s6Q@Io8E3L)dqcn2s*Q>;yJ(jR_L4emhS=qd|-SA;AKM%>TV=)2Vc&+4Uq*8U-S7 z>JS*jXb38=$N0`0OtPwYY|b5zJT~`^`vGA3tXuzM6FXzpt@gy+yJkNz=dO<2n2kB~ z4kNL!lL3f`1nwZ!Wyx_$^@`rVZ$k!ty8rb<3D-l zpMKa{Qno(jfhBQ31OZawzd_Kf3$pXxu6AtIc6oeaxA&y$yT+I6nj|5nd}9E>2@n-V;G8n*S_xB^mt35aMhHAygr%&?FUzhzi(9v$34)3Noa9<9}Rj)b7M=Y}>Z&G-hMl zX>8k08ar*=*tXTAvF&7zLy)CqnRI z;BunBV+_bT*l?|o}u}-(N$edyf@0+(HHq=B4{05*C&XLhgay+ar*HJ zXaH3j4Td^ay$vBvMBHm2ibz4l4I&jxz-_!=iplTAK`fO^b+DuwL9eS-FMc9Bc;J9D zjMbigov}D8NciPy5Q{#7E%I*-O@4e#dU$w08Co<18`2PqJfXZmYg!P_bd+d`>NjLg z>e2^zD>5?}e<-JuB!>==HFyZ>umz2E*)|XIs#834Kia-_$iBixOC?L^Ssr#Xd#3m; zyR;P-1eHQXBw!ApTE*kLIO|9I(O3}?0ZGQD3Xj0<4MiJEBHs#b-)=nq?+Xqq36gRb z(>R&^P0@%t(ugQZd3ZRkLTH2PSEXZ~m+;fT80(AGZ2&lvL*sY76@1Y*^1tt49zpo7 zJPlde-`7%)jwknhnVcXf>DRe|kk z(7cYt--lm3ChSto{1V=RsJmx5vjkzWYG4prL7!A4a@`z{PHA2pG|7XTe-G}0jz7|v zQ%A?nhM8DQFF^^GL#U}@jFLbHhnwl-7r!bzEE`COuK>znGKW{U{N>yGni)L%|G8A-KhGnGT-@BPpt?3NQa zAIR`3?_-#r+#T1N(%5fUaK=81%H+v)g)G{^t;eIW=qjhMs7*)0ZZ|n_DtNU_u~_K~ z8rX2V==R&|WiuM+%c;l(qp1*9A$spMOxboh^}8Frlucod8Of{( z|rc-JZxVy*^HmrIfwvk7Vfq)cT~!B zXa#5Ffk=I-5!|By!iz>!@R>wc+yIu6P4{r$*7cf+90Du0tYiJOIu`2oy3e21IYb2! zI;>U#K1Gwb(}0E=!Q<>$E02AZ2^@+g8~kkuN!#mCVI!hrInYCL5HvFnDL#K~d>3MA znO}v|N!Tcd-eZnNR3){PmdFo}ea)_q=72$yNDD`EoLlm?%C$tQP{54w>KnzG7^X&R zih0O#5*%%!mxosGY$AXN(a2zu9~mHr&r#&Bk+=phalh!}BbN+HVQ<5$ltvf9e{h?N zlr`glI0V8GQk@)sy8=RGO)j@G`HDsy32`EyyI&@W%(g*@`itIcq!A zJWS5$Vt438+~qmyJ5 zi5TzvrOR|$Sjt%GmnAi`6FOof0t$BF38^gfC zo;Wn@lBGsfD_cCu9|dYAPh7}(bSIG8EVcgN!Z6QinfneG_bT8raYfXRhf5M4BMUk~ z+C^?7wY8B$@sIUY)g9g(0mR-iL~ym@t`v2MgdCcpXz|*T6x9OVD(?RAWQ_S46o*n_ z+R(SZ@?0S?OXS8SmJrlm0;Chg=Jm-6hnAjc>pzxBF1SaHIXk*enmAmBf7oyiiJoq5 znpF6(rORZ(%VAo>@Qe4?{^T+L#a}Q)%`;k4M&s18>4!Cdq^YZ7ClL~@@t8xp;L=6w z3wrP`g#0)!>^|l!d>6ZdVf3IFH-L>T>KkWAgM5vH?0_kbPUf1!3nM*PUt);!M3f|B zgGLKk%?!;bKelrx=*bZWRHBs0BWJ_M^Ry25qF`AjfY6BHz28LS;Pb*@k{?ASGNV< ze1;v27=uNxyq1smzY|04${!DuVk>wfDU_08Y#X+G%l}%#OHwNs;9_LFb7- zv!0a4W21RCgCE{R2D{$|4SRVh92#%>_jOa_g)=ohGg^%aQ<+neoj8$oZ+rj-gq&uE zqzQnG3oXJ2%XBzYY);YcJQ;-Hb9*Zz#%1?e6&vl=;2?bQWogdn;q2gb>J6@Tm+-x} zU-cGMw9#ezeZ}Kv93$z6J4vt~fI=gR$#u~<^ZV>TUUAt@H8^JFnqP)&Kzv1*c=kD4 zdl+pkix-p1>A-@}y_`upMSff}@E$DDrt4e3!q8r=5g=Z~C>e|nk1T<4PIOx0 zu!+YwR?>|?&PV=J@^7I9fSFC#RwVz2hwx9iHCAK4KUqIIHKeultnB*1!(c%D=)9k9 zRQkHi)-Q95LWl&p>+Kdzk$|M`1tHPMC1Dk~U&GwH{*i2zWh(B!n*csF&F z*>Q{_rb?J{d8cke=9X8|4l}BrFS?&{p(+u@i}t41TPb}=XTYKEtMil)Yb$?B2dbIgk3u`R{()4U9AcZ=8H118z=rfHQd`g zVnFXs;1lh3X0?C7wMik%gg*S?FX@+ga?-v%zcsD3L}=z$!Th3}SOv0_s9-9!YHAeW zZ=JIiNx1)I9?t&~TR*75eF`#nK#>HQfuf)cx2Q;1(@-?E`^I@kghFW(VRoRcdo1;M zH)rS1Q)yvUouACKg;TTfl;^@~D2KCR8pifChfo_&K}*hV*vK6Fyqr3;II=0f*LTct z*&p`IH4^CT!4Q!Y{~9r0-Gj-rGGL$}<*>z_LR86%m=VPBhB^`8Y?+^Rx_xW0@QThDUd+Z-qej#4k?htPua5Cvr#ltXT z1jFII&ef78b`uvoD?(MbL7NRTI?;XN&r@4!I}@cGmet}TNr8p@Xib|XmmEG_JcHFZ z^E^O8tJ~yk?3GzwiXgp%KKz#49`UlpC< zR2C5Bbw8PP^D&KEfam2$aYt=n^T<06Tc3^DJmhOw7Ws`l!>a9Loz8!us$rQhC_ZH` z>PbEiuK7s|?6+?Het7Z`Hv5~wI-cQ&7X#piBUCiOeuyNVVQOL9_dmwH*X~me-`J!1 zPfn%SMSg}!VBxTxDzYQ_^kim$p@KGYloS-SI5hPaOZfd68#OYk>J(H`Az>&*$TBgi z#13xwjg)iC#y7 z-fuI{J5!F^+Vbyf-9z4aPflujcTt47k0hQ1MKit*E zHOR_g&RF9HzV-5#+BH>p-+1hFu*;_fT(G>Sz%>vl!Dghz|Phj%U)SAUqhb$h2scjLF){foWq4Ey*FOC6=Rs#%8YTsl5~m8HtVe z$XNV{1nO$>Di^n9>0BXI->F+}5Bv8m1N)!!UUifGRMr{ z<4ExzsUy3SYEvN(aR6G&i{FRCokn$e%uxcqaI#m|FL5NLT9`tRN2=}pP=J`_I~@3% ztChz+5mom&3q|@i)+YM4ebM_8GUW8}!Et2Mm6jd>)E=DYNXqo#nK2&^MK@Etwkr>iRYHN93b3lJfH_|CEQ9SOruVK8$( zX2HD1{wQW@)BWwTp!=r>3Jitpvwu9N0?1IsyU}41;^K&EP2ee#wAPYnn4nRzPm=LN z>2P0&B+2EL{19q-Z%dtiSd86T>|mhi?WPwXgjY?^=`TVz{yCwWC`X(^)fAVoP* zwf}3X{B{UDS2}VUX#|ba)%+K-CN!!`;6nN`zb81s<&@?2hbc1aqTWVQnKDBE_D6^< zF-aB+JGsx@9@WKB^v6_;r2z#DWWvlkp@`>$FPJ*p$0gARtG3tz-nVzYWQ^u1fN=yF zJjFQ~6TP0ztA7qmlX*O{Iqxk&ct?=w@uCu>$;_@i1m;O{6d8p8SJygFZpDf#WeKb3 z_*jiij10}=>k2s@lShjhC|G~#P`Vh99}F297vKZ|ZJRB~*RY(hShA~@%?_Uu#({$wZc$wgewSPoP zNc$LL5td6hnf$nil7=~`<`G>Rwc*oZzCw$qvyS{Jzb}=Cn-sq_<+Bsit?Tfer|jmPVRUm1z;j zQ}_6*y_Up&4^DR6auiJ&?y(Yd%35|T(triyLmR#J_bgz6C>SVe(FsYpqYg^(yEhn* zu5=Dpm$WS$DOpa3{Gvjd#8BaZ`z38oImM=$X_IT}lrp55>1)hNmn&5=Z9DYh$-;t! z|2r6f&-gtE<=4{IPb@xE7t*D4$>91EgFe;; z9UKhkQ&uFZTsd(L4=1pVGSN`Xo`p8W$Y^6ydgSY6J(kg*+uj>%U9Vlb#{>E|{l_!Y z`A=FS%XlXm%4}lz2L9dm=u&TC*zBqT zIn#nIhA){*7}^iS%q`Do`H_}tt*&gP*(rt3G z)DH1WGuL+bRf@h%13f9U$=HAp+*wVQksoNgk^ugS#|Hyl^<$pXDKIKvnayKUC$OcV z{$lt|o8}u&jp$C^%|DIPDg8Di^C<%HX##^m2;=d=Vu-R_2QZUrZsBvB7Z|^i7v z@GauL62rzq;&fBhsKd@};#U34(=rq#I9uRCj^MD6hr}F^Fm_?{KHe_ntp&0;9h=Ml z%_!?5f=s9qm!_YmlI~+=OUA9D<$k|#Rt^Ny9H#v4x!_p%Pl%+Tx2H9saV9-Py59B2 zuntzq{&SWTxG7C6=rT+3xK;)WolJJz_}5TA0G~^eaHK&h3l9YBR4C@Tp&2>2?xp;t z1AI#D*${-xJa7}5PWK%1@P7+~pGoV2~cdi9J;-hYI>c6k1tpud+VdIDtrK~1X zz^oLThGh%vW~@JGKYkpc!Ts zhr}V!ks~Phl-7uKembjyE%NX`#1NhNqQA^v#n436xG2<}gJtpgW_BBS{<;uN*wP6oFO?ZeWWeAJ=s!t{>91zEzy18{cjNuHuIBR7XVkzR zyrXhTi55X#3N0C@OuDR1b;(xSAKe&TQ!4y%8>)ot9I00u3!A)0)d*V37d=@y7)?UH zr{n2I&sy%m%RBqAfc!J6+uTeKFaN^JyUPSKXu9W|C?GzOVqWqOUrt|aU-MiN_UVpg zb1(42ZjsH7pe%hCgRI}wIOoIP^6c$A>hloPb1zE>C2OT8%ozrABTo7HqwgiE@a@9S zAMeVe5R|2F^E}Yf+^oCM>cWpPp0ixhv2ZFt&?oxNnbDQVFn>c6*lzm{H`ej#aMPnE z$F-5$flaetA9#}H+~xcF0Mz7R{<_VTmpk{B2Jrf8W%!ZZS{Q8;@`4^Vsc8GuFSqS^OtG z%jbYKPC?fi<%h>p)n0DS0!i2O^jjWv!Sf($&skxmsQx++%j_bBo_FXM-axxUj%l#jUxq3eW8+JIg&5fG!%Q%>LO@uM~4-%;u{ z|JRC>E8w`IKIQQS58)$!d*Sn9(%X9ZQejV}+XQ!E?|BYLL6@Zvzcr9i zo~D1z=6 z!%&VQLUZ*vdFjI1UOV{!&xC6FFo)~;?2f3euhnD#vN;LtKaTyf)AnENL>?FCY)6uj zfQ}EwQkOtM3#B5%r&+ewF><*itXTWC*`pcqu@g>8?0GJ!)5^)Ja4nnUa4eEMhX#O2 zPCtZh5U;j9qcB<`dPpIMv6nDzugQfuMBd1U528PSl6JOoaPqB!xg;A+ei1nYQVg)HrkhA9Yt#Vu^9$iwQdKS$;d;2#O~kS%;4J~Ibf&=e^Lx*H!6MKUmtt_IZbgG~jy2 z@F9Nfefg0cYz#+8OQmEjw$O_vO6FuR z9TK;K)5u?H9bhw#q_9tcY=Qr}my&ezWk{X;K4H?xIE5f` zNOFA+`(q$?$(JGEzZG%sx#2=1Xinsml23b}2X|0??d-j}-~PFHN=%r<2TJ%nnNT5W zx&fPm8@2TSbO#mx;Ww73*Iv5&@Dmc~giKg!QWvuFiqp^k6@bi1Wd9QPve)cMbOy1j zpSUD^GfGkTUN4wNdOz2cNy8I(E?fD5Z=|9C7d1Yff7=5qk7 zK?DEMFpQ>4b?%EVN!JLTY+Gw53%tN3Mld z5vyd4SYOobyQGSsT|~=`4eb__{6sAGEJZXnxr;Z=W+{;ptN^@a>LFPfg!%|*cHDv1 zMr^jk8lyyr>oNIk#H}(yQVd0pVkS5pkfj;=l*y@g7vw0gzuDKmg#Zp)mJuz?)4Agb zDe$nN&`CfcBR>hWUFAqoRI?1?sT5z0YY2bftpMJ3xRjtp={Z<{Nw)!Fw9OX%0rX*cq$UZyTQ!1?zd{Lh7Il@a z#QjnvUS}6th5vOiQxp;fw5~0e+U7s2lyEo<5=4kYw9VQZc3DBw_hM@zp#bF!g`;b0 zDX5u#nvfXPYZx7R>ogl!AJjQzxu#TBqyw`_WlJA5m{*PyQ@`tn`&HKl%d7}jWC_3* z3^+x?=r?YkH7I`BUwLQ=$%+MjUheYm`kbZ12pLDEq2>>%xe6_DY2GvZQHe~W;6)+HygM}fR@&&~|Ad+hE z7f-QFVJ8=Ot{&YoEXA--r?Oc^4^UBci;q20X6n$6xFRhtlTU7=@CSO~q}d`E3mg&e zE>RR@6eDTSCz=TK>n+wMFKbX<2n`2$GyXZIh>pw1n!`5VLWi%Ql-Wp#FD7q9cZo-H z3B=N8bbCR`ltzzCtZ-eW&8=U_%kF$kgEh6KY*&KC4Gbo`>1ycG2rHgmQD=aK9>k3D z9y3(K*8gS%)>M4Q+9pdq-nR|KR3>V%*}w3!bc~d2Wn~%AEw^zgBPFv~DSk_|9Pb{O z&vS-k1$_0_dxQ^zVL{&yv`{gT_{~gSNk+irZVa%0)GM%_{)CnmMW$JjFPEISdIn)z5(}QB;(%!UTRH^bQcOv1d1jm8*ex-_u zU}W}RVqLM*tGKK?wxzUxhAZ*=8ZVNToFC7DDTm>##7bIn8obcWu9W_H==ZQDdOZv8 z4#@7h3}>A&^xi}_pX*y9G%QPj&M2*)HgoKva6*M=Su||Giu$s!nTKur46}5h!;sO1 zI>#?Cf#o0Y)7Mq?m?rtsL>*4KrD39uc>SLTRU?~SSsdRirxYC=UapH}JR1*aZ z`Rokj-{c6j=@}yzW6JNnW7ds&w)pW)+F* zYRCY5b+B(8_RIyUrFDH&Ljt@e-Q&MXPSCNk-=k%!!J*Kn8Zb3R8MAxsxmtg%?-IUr zn?MN4N~qUa3U(x9<<+#?pl>ZjyTPIesHd7APE5wU3PIgI`9RInYgMn_RH90ML9vQs z@#I36XinFBPE%c0tVh7G;Lvq^?_~P#_4h>?sD?|iApM2dnG#4Wl2R3NxGnOK`zkbC z1gk8}Q@0>bdaJ+14!76cBEX$g!L4`#U%@OUf2kOvLzHr8T{_}ZU$zs^l}T=`A{~aQ z@SIi{5RpDisjMKNK|Y+3h9we0yg&AqHKO^vQu`+pT+Lq#e7C0u<-p+{oy+^Z;>p}ju9u0oSOmt-lba5 zIc5D@>BJ+d_H~XwF!|uwaD@jnquWLCjY3F6Ne~jkomBDmDUJDoum?0S*A0BTQTcom z4sjL*wfC%TYzAm^@z`@VGeSdlc=6L_)taWrm2I#>la|5(%AtI{*CsB-6={()n3$% zVRAS8_d&VC)erN>x;0@_U3=Mw_mhI|o!n)jAL@P0~$m=2LMDN$l<7*-uL3 zVR1 zx8S$r*td@rPUC_=^J7?HIKNv&2P_t!sDo`XjNtY6=$>ad?aLTHcT^)#L7yw&HE-M0sn(6cntW?$erJ)}KXCp4dXyo>&FO4DKwxMZ{;g=B`A$J77emu{GHIwL?3 z6y5tNe)3|q@WBjBn{&S833}PS;lGhx+Hv=KI4TS}yZrEbUmlp5-dvh~DjQw=m<$Xq zPcK=N+N*`yiwOpy68+P@@tyM*?e$JlRQb4n%!MLE;lEyRXY_j4tX3#3D2hsOY5bW&>5U@zCa0hWNhAnwD&2943?dkRpmTfu}aQmT(-*#q%*5Adq z*0xUc@^B%yV~e$aa4>#rL z*4HWzw1GqlCK^SimlnJkPopF5-3ym{UY-4wKc4h0;I1)CrM|7le}C7wFrdEx=%b#t zfgAsa1o{Y$>W^JBwCJAC#1e^*3j#s;P||mQ#hNFN){%a0Z;sHe zHnmvFfKxy+VL`zD)LNbH11`Nxjg*F`4AhZ$@({p+)|Pr-&m60f`-}Xi+h31BA|26dUh8N6U2?3S$~VyV(za;Jp(i{4>lf0-yTd!CW{8q6677a5oQEjc(!IkC zacsp=fj-as<~!^yoB78zl174UYc?~C*0QBp+2v7q(N!POc{+#45+^O~dy-nwXvFFU z3q!@W5FPWt44*xC8Pp9`xrJ#U%#<@w^Mp6wbk>Z%^A7=BM!Vh887<}->FxR%DSHW>` z7VIW(QsO8-nC-E~@F_}#mxN?%dLSg8A;29a=qEJeV4$qTpeg%d z)Hvc?@)tO2T>=K?*vV?PoBQV|64+Hz*JlkNxZgomXLh!?7oEf`fc5zD7MX233~i)* z3ZH&d5b`jaU$p{r1UWP?6c5vm>?@k-wM9IMYPt>$_b!x-&Fr?L)06cYap0)h(pXD# z`yGt6=qP4)KIKjvrZLZz{LS`4h78}lFZfWoKjKG5lm5Yr z@PTRfedQY==@_c}#-OkTV2Yn4EaI-J3 ztp2A;4@-rA@eP9hRExeR%Zi-FuDV8gY)w+An(Hb}yOOs0G%TNo^_OIjqt1b9ucc&~ ze{kfZ0E8GVg}+O40(@P?DVD<410Lq+6dCy^(zrq40S6sgt!^OVW=} ztaU#^i!RB>!COOUkHM9RjicUPAXRq(c3=e* z9{a&51$M#;6f-Tn#OP|0=uFhYsTa1enL-oO_ z%QGfp zX%@Bbvq1DIkyPjon{&y2N2B8|nzOLI^_$O2)fAALEZLI9A0^BFCUtDP>{2W=L``^_P#iUvqH#+Yb`))Ke5d0dR6 zoRoNJHr5$4;w^vo-*~D&2uw9&<~V_I+SC%iGyH>9g{MKpg<99-)#N8;i>2ksUPpcq zkx}Es1ovOGjuAKcz57K(-@R%tA~N0aVyRYuDZ}GZk_?OG24N-t=mb-!El4dM=lN4k z1xr|kiMolp)=O|Hy1B{R68&x{+*?(l>7lsR;uE`pn@%_X;0ykKC4GEuc&TzX?(NL+ zv7hvzrbHx}g&)Xi*qVC4&y@rd7tWI$hYzCvX8ln?A@a#N7G>pF z6&;F`!pp$q?qTFOkT7?#siK{_-#@3W>!7olIpG(PrHh@V_Pg=s>z;~y(BF!=F4^t| zUD|>ngT(2b2K`8Rm!VUgW_{+2%ak}1`m&^MDsSxVMo$v$c)Rs% zei?5r5K#nSUT`Yt;}QypQ6yr^-LWBzP+}2~0?@8CuPF;DfYRc3EupntyBusYSNk+VT(Xm{b-8+iYvW*sT*(c9KYl?VYsQR72$HZ|stO*PA}8-V zS=Yzeh%$>F)^K{PKk2om{0!nxn}yOo?)&#+ida(o%aM2{UqnTkR>3H#mSnq>U*V~D z-INPxK`;ROn2L}=0@SRQvH4)W!KSq?v0LR1Gv40QFMVuN-{YT9%GD8LMt**o7$WmX zI%M^vsZ{!)PPtP)=N0_lI` z=@@I^hw^~I7heOSMD|y{;TuU?L`&9!Gd^>&mbh4ZpMO(PXl)hY zVf(i9yj(1}zZ|tw*zkxm&4?p|7;5a8NGv$IISp}Rhl+Z%GKs+~sRqy2R{z#g$;o7) zNqg!^3L~6Jx8(|4#=7p-V$(DL=-2RX{k+_ryq4qAv{IwbZRV)_rzk=cQP9FeRDQR{ zeu!Xh8kiI=uf6a|Nx+6>i$!Iti!|bDDRmf z{c@4-1Y#yxEDG&^@n0ns-p*fj9{XK2{hg>i5Nih|*VV(55C3%X1o?qy-ypcjdO#eF z_W)7~6k$W;D*h0DCmfl^=Ep_!fEVV=zZR^Ab-8G z@$I>iL1e^6HYFFEY&+KT@fKZ{9<+joh$44>C}{ea=Oo>Ee&>W;z__~;pG`;YkRTgl zk61mxKlO#Q%6APkdf`O6<#o9G_``f}oRcl=u~;#dc%-tP+O?xM{!Zw7`oP~(jH4GD zC=B?6>Vt@$g(|If7f>y(sV+92pL$aHG3vw`c)e`Pl=DTl@F7}lU$F?8Cx%AqT1I!z zG<1yYeo-Y~Ewar9_h+;wfjY&8rzFYDn+ar~b;xsmX(8+ z38d>Nj{IZy5iy zJ*s*z7L+WQ>y0y9WisdqD`M0aVv_bV;Mkwx>erRxS5j&wc?`PloQT+poGI*hd9^?0 zH3*7(7TVpmy#lXK^j{WX=nxH=ImJ!8=$&53Dj=a&r;b!((dx)#5i5#a!4$N7WT592 zE3ow85OMf^G?ArT_?K%Z;80Npbotq@!Xt;udVzf*q@B3+8=fz2IuNh;2Y4;{Pm^G|I6|D_OK&z@ejL0 z&}M9MV9f~UKM`p**?-;`pZQtHt! zaVTM8Z>U7mml%j_nCa9brk1;bkDjdDC)@<%S>V zdZXvh)lcyJWV>n8ONxzbA2>}dsRMpl~mU4xQI0r$=gL$y%aaIUBXZOJzUA0 zK?fB=gnuJVAVI&dV%*4*>FJ=`uk3O}GwuIoMiZd0w*(N^@?1vA+?x9df>@=rhm#5>@zc`|Z9v z{Ss};XizRLPYT{PGcoq)cbqyoSInsZdAa(Ib8P3w+xg?QIhZZAa%lGZ<+kQJ4=$IO zdMgv8;f19ke11w^Du|%r_?beSiBY8PiJ7PT&p~k?uXNOt%|5PlhN5wG*XsND76)6C zl@bQYjxGqU`Rde=QO4bvi1g`o>Lf|v^Kd3A|J{8}=%B^E0>vYW^Y5(C*ffbMRk_(g z4AV9nW9-kog;s33Oh)vc(V0IUTl$~&dmBTU6w?qUH=kbDKpi8``>A8l-ISl6#U~g2 zuV(cQ7&@lBX#Ab?9A=0)Y5i931WRhhAjVTg9a;7#7v)gS95T|kS%#B7yuu`B4!Rb> z4`CL0q<%0|`_pP+S3N=1D|%wX`-6$b9fB;+Q6RI!>X_}g8;3XYDH*!W40y z*=6I5h``_dRoHbkAN?5M(l__^;yn^k4|+%LgBIhO4H4s%{a%1{#NYW0ky*72NJ%3v zy+ToJyP;}_&aLn%@6fAC;)kN!i=}JCn(j}Z)IGdE#Uf`M_dVCpf4#0|WD(jc{GWe0 zGcp$N@xT*k^!(=8rk}CjUcC@jOjYWwsfjhUiMIZ1xn^qHP08PVk@;w#bFJ5UcJy=e z>C*EhCd(n)!ADXCVJEh+u@XzBQ(?wd7p-v#)peG9O*$BS<32{rn%@#@&DZ4X&Z7=1 zup3~pMmL3Q6CS*Z^LKR!z^xhle&E90-`^XtuD>IC2k< zN{oeTcy2574b^rNMK~U@h6M*aFGnb;bmE5b$i!cf)RH%ya49oVO7=D~ST?5y=?Gt4 zvLw>Nek3z?DXyj%zbsfB_$(ngF{ZuD^rhK~-v6N2JuCpE3Yvw7jsS3xzdg!$XQCU} zmV%V(y<~s+9lL^BXRW2?O0igN@xPan|G=OnqH$k98S!rSJLS|r<`wn38leqz_PwgT z%SKW@lffkc+G8H{MaM|oJ$7WRHU^Ixy0&Hw>#=T~s4ve#3>gA`;X6(R)NM*@h6JLT zBu%OKU1bXS=<|7)hH0Sy$L(6MTpzvBBV5!_bGD$dnJx0L63wyeExQ}YUDUsm#9dZa z$xB;olstCe%vfyeFP*?8{`t86O7IQ}=@Po7M3T*as39!y8YEd73$R}IKF#rK`)!Rz zJxi+nRZSePc}K$_hHnewIZeYN^|3my?(_U-#o89mbMO6fpJdvsSUWI^5r_M9gb-iq za6w(~@}6NXk>iNjX?XQ)18r?jpB1MaeP&WC^`v2USM~Y;OhzW*6kU4NXkI3oBtBOs zFX6iLm9VR58c8{5@n6r=3;gjSEZaLyA!E=@MmO0YtMaJ2K>?(CY;G5i0p=Us zBn5*jHbLbmi7Co)v07fG{c7@`8?*)XzUZxN<<;li{h2cP^@8%V* zLAUTTg_nzUADhQRvqI0gl^-AHe~JI)7b*GU82Di^{vLlw#l>+QS?ue4>+)-4qT-H> zdF6Zto$jzW2<-o&Mp!Bweto%q$^nlr7@sbTt{ zMS573e_;j$m*MAZWQW4Y804ru5G(wU*jv9F&b3Mb;0kY6Z{oJ~QE&?SZlJQ1U|bjy zh(2AX{oXmMoU8AC9G+{z?R{po+J4Wq-fpmbH|Jq;@Sl~qHs-l`F%0k(JZ@3ECd%3})@_<8 ziKvackGFZ$ag*A_HX;B(ntu5q_3Zyq!>ICJf5zRGVOY<1)LBPZ$fDQ1L;X{ffRN$G zEx+$XKVFQltDj`5pBhug@JZ+Y0qj5%zjBvS1^PXRT`oECHJjDFq*K3vsfqCok+3fG zIi?`>B^Ku{4dq6TV%3Gq7O{x|mcmG|=)_g@fY{V5#mns;f~$N!J`|xh%1L*}Bzwx( zf0m|A< z_QTz;JmWnpuRP_iR$h4Q3;yfcFFkzA=9`|>!(TE1{@I)6JDvBR-0RA-zCHc3cb0MP zuMzDAShC0~foOxXL=oF*+pt!1mI#L#8l*iRxpr$2Oe<4b3w@N%Y`ddpGL#tLYhHiM*{r$0nb-4rh)(^h-t{(oiNH#8l3`M75 z2)q&m72GM$p*-c1CY?fo+8X}tTL`jY%%d*mPzcGPOpkG&!itLk09_8;xn3@Jh@({C zxmXg$1WQn#1)6*^DN3Og!H?MUw=IUgRUY-RzvFmxw@lEFN4Zf15#d+18qBWcZk!x&nW5va); zL|RCMyl&M?iQ$u`vmvpsH+2 ziWv>1ff-XNmtnM{3ELpDZc8RNl>5?@G!*qP3l)Mjx}p_NK)3=7v=-@2^GBY0ZXCeU z+4VsWm^IJ$3KzRd>=|Y637|ges3SXCAk)%==y!s(m!7nK%|$1Eclz(QhdnMlVV!cmAuh2aW+YH( z+R|#bG;~6__>9Ug&{|ouByEZ*9b{!BZu|vfkWaa;5{u`@BMDTH2y;S{ZsC&Y^|qJU zxfSnIJKDVXK1I+ilvJ3IGilKaf7mx-pBQTAyCpr>mAjTI(C@+Qa?!Du%w6=lXKw5k zo<5e|?bdDq&6G122bTolkq(_dgoK=7eMc;`Y*kUOQa&Gb>*2O15Sw@rH^l{B{uHiO zdJ*!Zn>$+anE4~mJ?^&0yfv8Y-X!M)h4lbM{5X1Bp~T9G5UWvo=Mm#eW}n*a@{@O% zD|VotbRUkHt6+4}D&=Z%QNlbegFv8CKV1?WP!iy`h8k0GZ5AaVLJcSbV1}liQp~6x zlrNF+ogmML872zBQ|kSr#~6UpnXf6i3n;=!*eULUy8t&v4_J@e8TT$LO6;RVGD27a zj22COI_t;tOFCaM9YRFhe0VPfMP2`(5|`vO6mL`c+p8A(?laTtZ7-vDy!xB&{uu%U zBXkoJ0wdQZ!Y3YmZfKIF(up$kPH{=6UAc>?0{y=MyIp$9hgV#D-19ek_vo?mYrIJx z$YvWn_f&Sk#gfH@p}q~NkqF96@s|>^-)dJD5fZLJ0ziytm0~hk(*iWQmzHTw>GO>e z_9kRmXuvZ!9(KmB-u{SxGVHs9w z^eON2)!~)kts+-N@D9$4$ONXM7Yrc5u{48~$>ByvxjkX=7R%TS@C?c$#)_g*(PECv zcE+uLJdS82LPXcJNIoQnr2o>$2VmT*V#h7x*y_d?oU_}e!_Rr-mS>;*^zjjA{L1Dd z&pvz05$F8t_=vOr5w4#h!t+2N!cL6DQRO~dB*j&Z>~WtgCC$t%sbz9w+yxMfi_MDS zO;bG2@$Nuk^d5-n6GJxKy!VycpUwYcQ11KdA_pgQve+6NNLD&5g#Nzx_d@IoWwKyp z`B4S>e5&V$`;AVxAd@#aVGdG+Nis?9a%W_U$Dk97 ze(+Ruh#fX`hPzozNmOY(k#lhevuOB=nm3QlNM@j!CwIhz^-%QI=ISW=47n7RA#^m;pjHJ2WLQ%1iIh^+6hoWd!}z7O|6pT$0^ z0O%e~W+EQGq@B;#-z1t%kfKUCeue8HGW~}HCMi1NMVX$7Xi6s64yA1)-=YMJ8H$BK zlQD&tziAX!dT||)fR@zjWQX&W1D|Rejyz+(jfb7`goQ&-JAC2LvtBSh^4#B6hA+4hY|~hm>~-0;e>~zZ{2>i9fyoR z4EF#c_rr@zeaMZ7(8^*@dE^|ie$PmQVp&;M)VuQEl)c|~##O5>JNd6?FFo$)TNXAx zs#AXILY};F-1V1rp1guy{XT~2T*ZMJ?ZYg*@gAyElmRU*NlYu};x~N;dEAxKM!%Hl=@D1>~} zr$*_ z{D;WB7N(ZlVUYIaC|&cY^Y>ihj4|qxKzJ_@ld1#@g(n;gTV+cml1J>cZOUL75Ghfm zu?x(IrWvx{qnS{4q$Ot3ZxgxqC}k94SdB?t7du9igeHXoV^-n~KxlJ2mQO$Y<)d4k zed<%@k2veBg(J@W_}aAcb1Ry;e{WNJL4y6?7WR@hwU14-hb2qsPT^b zZG?=3d#J==wMR_d^G(z1?I@D`+cH8_3WYEIT8cmWZuECR&@?-=02}Y1B3=7UTF~`o)F^#AL627yw5D3^BSq z0)Bnp?KFRH172H7=R`T8b!KV4QOf*~QjDC8EQ09Oy_nW~$IQ-+0J9_r>T{U `k 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 diff --git a/docs/assets/style.css b/docs/assets/style.css deleted file mode 100644 index 697875b3d..000000000 --- a/docs/assets/style.css +++ /dev/null @@ -1,86 +0,0 @@ -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } -:root { --bg:#fff; --bg2:#f6f8fa; --text:#1f2328; --muted:#656d76; --border:#d1d9e0; - --accent:#0969da; --accent2:#ddf4ff; --code-bg:#f6f8fa; --code-border:#d1d9e0; - --sidebar-bg:#f6f8fa; --sidebar-w:280px; --shadow:0 1px 3px rgba(0,0,0,.08); --radius:8px; } -@media(prefers-color-scheme:dark){ :root:not([data-theme="light"]){ - --bg:#0d1117; --bg2:#161b22; --text:#e6edf3; --muted:#8b949e; --border:#30363d; - --accent:#58a6ff; --accent2:#1a3a5c; --code-bg:#161b22; --code-border:#30363d; - --sidebar-bg:#161b22; --shadow:0 1px 3px rgba(0,0,0,.3); } } -[data-theme="dark"]{ --bg:#0d1117; --bg2:#161b22; --text:#e6edf3; --muted:#8b949e; --border:#30363d; - --accent:#58a6ff; --accent2:#1a3a5c; --code-bg:#161b22; --code-border:#30363d; - --sidebar-bg:#161b22; --shadow:0 1px 3px rgba(0,0,0,.3); } -body { font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Noto Sans,Helvetica,Arial,sans-serif; - font-size:16px; line-height:1.6; color:var(--text); background:var(--bg); } -.layout { display:flex; min-height:100vh; } -.sidebar { width:var(--sidebar-w); background:var(--sidebar-bg); border-right:1px solid var(--border); - position:fixed; top:0; left:0; bottom:0; overflow-y:auto; z-index:100; display:flex; flex-direction:column; } -.sidebar-header { padding:20px 16px 12px; border-bottom:1px solid var(--border); - display:flex; align-items:center; justify-content:center; } -.sidebar-header .logo { display:flex; align-items:center; text-decoration:none; } -.sidebar-logo-img { max-width:200px; height:auto; padding:4px 0; } -.sidebar-close { display:none; background:none; border:none; font-size:20px; color:var(--muted); cursor:pointer; } -.sidebar-content { padding:12px 0; flex:1; overflow-y:auto; } -.sidebar-content>a, .nav-section a { display:block; padding:6px 16px; color:var(--muted); - text-decoration:none; font-size:14px; border-left:3px solid transparent; transition:all .15s; } -.sidebar-content>a:hover, .nav-section a:hover { color:var(--text); background:var(--accent2); } -.sidebar-content>a.active, .nav-section a.active { color:var(--accent); border-left-color:var(--accent); font-weight:600; } -.nav-section { margin:4px 0; } -.nav-section summary { padding:6px 16px; font-size:12px; font-weight:600; text-transform:uppercase; - letter-spacing:.05em; color:var(--muted); cursor:pointer; list-style:none; user-select:none; } -.nav-section summary::before { content:"\25B8 "; } -.nav-section[open] summary::before { content:"\25BE "; } -.nav-section summary::-webkit-details-marker { display:none; } -.nav-section a { padding-left:28px; } -.main { margin-left:var(--sidebar-w); flex:1; min-width:0; } -.topbar { position:sticky; top:0; background:var(--bg); border-bottom:1px solid var(--border); - padding:8px 24px; display:flex; align-items:center; justify-content:space-between; z-index:50; } -.menu-btn { display:none; background:none; border:1px solid var(--border); border-radius:6px; - padding:4px 10px; font-size:18px; cursor:pointer; color:var(--text); } -.search-box { flex:1; max-width:400px; position:relative; } -.search-box input { width:100%; padding:6px 12px; border:1px solid var(--border); border-radius:6px; - background:var(--bg2); color:var(--text); font-size:14px; outline:none; } -.search-box input:focus { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent2); } -.search-results { position:absolute; top:100%; left:0; right:0; background:var(--bg); - border:1px solid var(--border); border-radius:var(--radius); box-shadow:var(--shadow); - max-height:400px; overflow-y:auto; display:none; z-index:200; } -.search-results.visible { display:block; } -.search-results a { display:block; padding:8px 12px; color:var(--text); text-decoration:none; - font-size:14px; border-bottom:1px solid var(--border); } -.search-results a:hover { background:var(--accent2); } -.search-results a:last-child { border-bottom:none; } -.search-results .no-results { padding:12px; color:var(--muted); font-size:14px; } -.theme-toggle { background:none; border:1px solid var(--border); border-radius:6px; - padding:4px 10px; font-size:18px; cursor:pointer; margin-left:12px; color:var(--text); } -.content { max-width:820px; margin:0 auto; padding:32px 40px 80px; } -.content h1 { font-size:2em; margin:0 0 16px; border-bottom:1px solid var(--border); padding-bottom:8px; } -.content h2 { font-size:1.5em; margin:32px 0 12px; border-bottom:1px solid var(--border); padding-bottom:6px; } -.content h3 { font-size:1.25em; margin:24px 0 8px; } -.content h4 { font-size:1em; margin:20px 0 6px; } -.content p { margin:0 0 16px; } -.content ul, .content ol { margin:0 0 16px; padding-left:2em; } -.content li { margin:4px 0; } -.content li>p { margin:4px 0; } -.content a { color:var(--accent); text-decoration:none; } -.content a:hover { text-decoration:underline; } -.content blockquote { margin:0 0 16px; padding:8px 16px; border-left:4px solid var(--accent); - background:var(--bg2); border-radius:0 var(--radius) var(--radius) 0; color:var(--muted); } -.content table { width:100%; border-collapse:collapse; margin:0 0 16px; font-size:14px; } -.content th, .content td { padding:8px 12px; border:1px solid var(--border); text-align:left; } -.content th { background:var(--bg2); font-weight:600; } -.content code { font-family:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,monospace; - font-size:.875em; background:var(--code-bg); border:1px solid var(--code-border); border-radius:4px; padding:2px 6px; } -.content pre { margin:0 0 16px; padding:16px; background:var(--code-bg); border:1px solid var(--code-border); - border-radius:var(--radius); overflow-x:auto; font-size:14px; line-height:1.5; } -.content pre code { background:none; border:none; padding:0; font-size:inherit; } -.content img { max-width:100%; border-radius:var(--radius); } -.content hr { border:none; border-top:1px solid var(--border); margin:32px 0; } -@media(max-width:768px){ - .sidebar { transform:translateX(-100%); transition:transform .25s ease; width:280px; } - .sidebar.open { transform:translateX(0); box-shadow:4px 0 20px rgba(0,0,0,.2); } - .sidebar-close { display:block; } - .main { margin-left:0; } - .menu-btn { display:block; } - .content { padding:24px 16px 60px; } } -.mermaid { text-align:center; margin:1.5rem 0; padding:1rem; background:var(--code-bg); - border:1px solid var(--code-border); border-radius:var(--radius); overflow-x:auto; } -@media print { .sidebar, .topbar { display:none !important; } .main { margin-left:0; } } diff --git a/docs/assets/template.html b/docs/assets/template.html deleted file mode 100644 index 64403d435..000000000 --- a/docs/assets/template.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -{{title}} - Squad Docs - - - -

- - - - diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 000000000..83a4ffbcb --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig } from 'astro/config'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + site: 'https://bradygaster.github.io', + base: '/squad', + vite: { + plugins: [tailwindcss()], + }, + markdown: { + shikiConfig: { + themes: { + light: 'github-light', + dark: 'github-dark', + }, + }, + }, +}); diff --git a/docs/build.js b/docs/build.js deleted file mode 100644 index 9305ef238..000000000 --- a/docs/build.js +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/env node - -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import MarkdownIt from 'markdown-it'; -import hljs from 'highlight.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const md = new MarkdownIt({ - html: true, linkify: true, typographer: true, - highlight(str, lang) { - if (lang === 'mermaid') return str; // handled by custom fence rule - if (lang && hljs.getLanguage(lang)) { - try { return hljs.highlight(str, { language: lang }).value; } catch (_) { /* fall through */ } - } - try { return hljs.highlightAuto(str).value; } catch (_) { /* fall through */ } - return ''; // use default escaping - }, -}); - -// Render mermaid code blocks as
for client-side rendering -const defaultFence = md.renderer.rules.fence.bind(md.renderer.rules); -md.renderer.rules.fence = (tokens, idx, options, env, self) => { - const token = tokens[idx]; - if (token.info.trim() === 'mermaid') { - return `
${token.content}
\n`; - } - return defaultFence(tokens, idx, options, env, self); -}; - -// Nav sections: directory name → display title (order matters) -const SECTIONS = [ - { dir: 'get-started', title: 'Get Started' }, - { dir: 'guide', title: 'Guide' }, - { dir: 'features', title: 'Features' }, - { dir: 'reference', title: 'Reference' }, - { dir: 'scenarios', title: 'Scenarios' }, - { dir: 'concepts', title: 'Concepts' }, - { dir: 'cookbook', title: 'Cookbook' }, - { dir: 'blog', title: 'Blog' }, -]; - -// Explicit ordering within sections (filename without .md → priority) -const SECTION_ORDER = { - 'get-started': ['installation', 'first-session', 'migration'], - 'guide': ['tips-and-tricks', 'sample-prompts', 'personal-squad', 'contributing', 'contributors'], - 'features': [ - 'team-setup', 'routing', 'model-selection', 'response-modes', - 'parallel-execution', 'memory', 'skills', 'directives', - 'ceremonies', 'reviewer-protocol', - 'github-issues', 'labels', 'prd-mode', 'project-boards', - 'ralph', 'copilot-coding-agent', 'human-team-members', - 'remote-control', 'vscode', 'worktrees', - 'export-import', 'upstream-inheritance', 'marketplace', 'plugins', 'mcp', - 'notifications', - ], - 'reference': ['cli', 'sdk', 'config'], - 'scenarios': ['existing-repo', 'solo-dev', 'issue-driven-dev', 'monorepo', 'ci-cd-integration', 'team-of-humans', 'aspire-dashboard'], - 'concepts': ['your-team', 'memory-and-knowledge', 'parallel-work', 'github-workflow', 'portability'], - 'cookbook': ['recipes'], -}; - -// Parse optional YAML-style frontmatter (--- fenced) -function parseFrontmatter(raw) { - const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/); - if (!match) return { meta: {}, body: raw }; - const meta = {}; - for (const line of match[1].split('\n')) { - const idx = line.indexOf(':'); - if (idx > 0) meta[line.slice(0, idx).trim()] = line.slice(idx + 1).trim(); - } - return { meta, body: match[2] }; -} - -// Extract first H1 as fallback title -function extractTitle(markdown) { - const m = markdown.match(/^#\s+(.+)$/m); - return m ? m[1] : null; -} - -// Derive a human-readable title from a filename -function titleFromFilename(filename) { - return filename - .replace(/\.md$/, '') - .replace(/[-_]/g, ' ') - .replace(/\b\w/g, c => c.toUpperCase()); -} - -// Discover docs from all configured section directories -function discoverDocs(docsDir) { - const sections = []; - for (const { dir, title } of SECTIONS) { - const sectionDir = path.join(docsDir, dir); - if (!fs.existsSync(sectionDir)) continue; - const items = fs.readdirSync(sectionDir) - .filter(f => f.endsWith('.md')) - .map(f => { - const name = f.replace('.md', ''); - const raw = fs.readFileSync(path.join(sectionDir, f), 'utf-8'); - const { meta, body } = parseFrontmatter(raw); - const docTitle = meta.title || extractTitle(body) || titleFromFilename(f); - return { name, dir, title: docTitle, href: `${dir}/${name}.html` }; - }); - // index.md first; use explicit order if defined; blog chronological; rest alphabetical - const order = SECTION_ORDER[dir]; - items.sort((a, b) => { - if (a.name === 'index') return -1; - if (b.name === 'index') return 1; - if (order) { - const ai = order.indexOf(a.name); - const bi = order.indexOf(b.name); - // Items in the order list come first, in that order; unlisted items go to end alphabetically - if (ai !== -1 && bi !== -1) return ai - bi; - if (ai !== -1) return -1; - if (bi !== -1) return 1; - } - if (dir === 'blog') return a.name.localeCompare(b.name); - return a.title.localeCompare(b.title); - }); - if (items.length > 0) { - sections.push({ title, dir, items }); - } - } - return sections; -} - -// Discover the root index.md home page if it exists -function discoverHomePage(docsDir) { - const indexPath = path.join(docsDir, 'index.md'); - if (!fs.existsSync(indexPath)) return null; - const raw = fs.readFileSync(indexPath, 'utf-8'); - const { meta, body } = parseFrontmatter(raw); - const title = meta.title || extractTitle(body) || 'Home'; - return { name: 'index', title, href: 'index.html' }; -} - -// Discover standalone pages (e.g. whatsnew.md) that aren't in any section -function discoverStandalonePages(docsDir) { - const pages = []; - const standaloneFiles = ['whatsnew.md', 'sdk-first-mode.md']; - for (const f of standaloneFiles) { - const filePath = path.join(docsDir, f); - if (!fs.existsSync(filePath)) continue; - const name = f.replace('.md', ''); - const raw = fs.readFileSync(filePath, 'utf-8'); - const { meta, body } = parseFrontmatter(raw); - const title = meta.title || extractTitle(body) || titleFromFilename(f); - pages.push({ name, title, href: `${name}.html` }); - } - return pages; -} - -// Compute relative prefix from a subdir back to the dist root -function assetsPrefix(subdir) { - if (!subdir) return ''; - const depth = subdir.split('/').filter(Boolean).length; - return '../'.repeat(depth); -} - -function buildNavHtml(sections, activeDir, activeFile, { homePage, standalonePages } = {}) { - const prefix = assetsPrefix(activeDir); - let html = '
'; - return html; -} - -function buildSearchIndex(docsDir, sections, { homePage, standalonePages } = {}) { - const index = []; - // Index root home page - if (homePage) { - const raw = fs.readFileSync(path.join(docsDir, 'index.md'), 'utf-8'); - const { body } = parseFrontmatter(raw); - const preview = body.replace(/^#+\s+.+$/gm, '').replace(/[`*_\[\]()#>|\\-]/g, '').replace(/\s+/g, ' ').trim().substring(0, 200); - index.push({ title: homePage.title, href: homePage.href, preview }); - } - for (const section of sections) { - for (const item of section.items) { - const raw = fs.readFileSync(path.join(docsDir, item.dir, `${item.name}.md`), 'utf-8'); - const { body } = parseFrontmatter(raw); - const preview = body.replace(/^#+\s+.+$/gm, '').replace(/[`*_\[\]()#>|\\-]/g, '').replace(/\s+/g, ' ').trim().substring(0, 200); - index.push({ title: item.title, href: item.href, preview }); - } - } - // Index standalone pages - if (standalonePages) { - for (const page of standalonePages) { - const raw = fs.readFileSync(path.join(docsDir, `${page.name}.md`), 'utf-8'); - const { body } = parseFrontmatter(raw); - const preview = body.replace(/^#+\s+.+$/gm, '').replace(/[`*_\[\]()#>|\\-]/g, '').replace(/\s+/g, ' ').trim().substring(0, 200); - index.push({ title: page.title, href: page.href, preview }); - } - } - return index; -} - -// Rewrite .md links to .html in rendered HTML -function rewriteLinks(html) { - return html.replace(/href="([^"]*?)\.md(#[^"]*)?"/g, (_, base, hash) => { - return `href="${base}.html${hash || ''}"`; - }); -} - -function copyDirSync(src, dest) { - fs.mkdirSync(dest, { recursive: true }); - for (const entry of fs.readdirSync(src, { withFileTypes: true })) { - const srcPath = path.join(src, entry.name); - const destPath = path.join(dest, entry.name); - if (entry.isDirectory()) { - copyDirSync(srcPath, destPath); - } else { - fs.copyFileSync(srcPath, destPath); - } - } -} - -async function build() { - const docsDir = __dirname; - const distDir = path.join(__dirname, 'dist'); - const templatePath = path.join(__dirname, 'template.html'); - const assetsDir = path.join(__dirname, 'assets'); - - // Clean and create dist directory - if (fs.existsSync(distDir)) { - fs.rmSync(distDir, { recursive: true }); - } - fs.mkdirSync(distDir, { recursive: true }); - - // Copy assets into dist/ - if (fs.existsSync(assetsDir)) { - copyDirSync(assetsDir, path.join(distDir, 'assets')); - } - - // Copy highlight.js CSS theme into dist/assets/ - const hljsCssDir = path.join(distDir, 'assets'); - const hljsStylesRoot = path.dirname(fileURLToPath(import.meta.resolve('highlight.js/styles/github-dark.css'))); - fs.copyFileSync(path.join(hljsStylesRoot, 'github-dark.css'), path.join(hljsCssDir, 'hljs-dark.css')); - fs.copyFileSync(path.join(hljsStylesRoot, 'github.css'), path.join(hljsCssDir, 'hljs-light.css')); - - const template = fs.readFileSync(templatePath, 'utf-8'); - const sections = discoverDocs(docsDir); - const homePage = discoverHomePage(docsDir); - const standalonePages = discoverStandalonePages(docsDir); - const navExtras = { homePage, standalonePages }; - const searchIndex = buildSearchIndex(docsDir, sections, navExtras); - const searchIndexJson = JSON.stringify(searchIndex); - - let totalFiles = 0; - - // Render root index.md as dist/index.html (home page) - if (homePage) { - const raw = fs.readFileSync(path.join(docsDir, 'index.md'), 'utf-8'); - const { meta, body } = parseFrontmatter(raw); - const title = meta.title || extractTitle(body) || 'Home'; - let content = md.render(body); - content = rewriteLinks(content); - const navHtml = buildNavHtml(sections, '', 'index', navExtras); - const html = template - .replace('{{TITLE}}', title) - .replace('{{CONTENT}}', content) - .replace('{{NAV}}', navHtml) - .replace('{{SEARCH_INDEX}}', searchIndexJson) - .replace(/href="assets\//g, 'href="assets/') - .replace(/src="assets\//g, 'src="assets/'); - fs.writeFileSync(path.join(distDir, 'index.html'), html); - console.log('✓ Generated index.html (home)'); - totalFiles++; - } - - for (const section of sections) { - for (const item of section.items) { - const mdPath = path.join(docsDir, item.dir, `${item.name}.md`); - const outDir = path.join(distDir, item.dir); - const htmlPath = path.join(outDir, `${item.name}.html`); - - fs.mkdirSync(outDir, { recursive: true }); - - const raw = fs.readFileSync(mdPath, 'utf-8'); - const { meta, body } = parseFrontmatter(raw); - const title = meta.title || extractTitle(body) || titleFromFilename(`${item.name}.md`); - let content = md.render(body); - content = rewriteLinks(content); - - const navHtml = buildNavHtml(sections, item.dir, item.name, navExtras); - const prefix = assetsPrefix(item.dir); - - const html = template - .replace('{{TITLE}}', title) - .replace('{{CONTENT}}', content) - .replace('{{NAV}}', navHtml) - .replace('{{SEARCH_INDEX}}', searchIndexJson) - .replace(/href="assets\//g, `href="${prefix}assets/`) - .replace(/src="assets\//g, `src="${prefix}assets/`); - - fs.writeFileSync(htmlPath, html); - console.log(`✓ Generated ${item.dir}/${item.name}.html`); - totalFiles++; - } - } - - // Render standalone pages (e.g. whatsnew.md) into dist root - for (const page of standalonePages) { - const raw = fs.readFileSync(path.join(docsDir, `${page.name}.md`), 'utf-8'); - const { meta, body } = parseFrontmatter(raw); - const title = meta.title || extractTitle(body) || titleFromFilename(`${page.name}.md`); - let content = md.render(body); - content = rewriteLinks(content); - const navHtml = buildNavHtml(sections, '', page.name, navExtras); - const html = template - .replace('{{TITLE}}', title) - .replace('{{CONTENT}}', content) - .replace('{{NAV}}', navHtml) - .replace('{{SEARCH_INDEX}}', searchIndexJson) - .replace(/href="assets\//g, 'href="assets/') - .replace(/src="assets\//g, 'src="assets/'); - fs.writeFileSync(path.join(distDir, `${page.name}.html`), html); - console.log(`✓ Generated ${page.name}.html`); - totalFiles++; - } - - // Fallback: if no home page from index.md, redirect to first section - if (!homePage) { - const firstSection = sections[0]; - const fallbackTarget = firstSection ? `${firstSection.dir}/${firstSection.items[0]?.name || 'index'}.html` : 'index.html'; - const redirectHtml = `Redirecting...

Redirecting to documentation...

`; - fs.writeFileSync(path.join(distDir, 'index.html'), redirectHtml); - console.log('✓ Generated index.html (redirect)'); - } - - console.log(`\n✅ Docs site generated in ${distDir} (${totalFiles} pages)`); -} - -build().catch(err => { - console.error('Build failed:', err); - process.exit(1); -}); diff --git a/docs/cli/installation.md b/docs/cli/installation.md deleted file mode 100644 index e61302183..000000000 --- a/docs/cli/installation.md +++ /dev/null @@ -1,322 +0,0 @@ -# Global CLI Installation Guide - -> **⚠️ Experimental:** Squad CLI is under active development. APIs and file formats may change between versions. We'd love your feedback — if something isn't working as expected, please [file a bug report](https://github.com/bradygaster/squad/issues/new). - -This guide explains how to install the Squad CLI globally, use it one-off with `npx`, set up a personal squad, and understand package resolution. - -## Quick Start - -### Option 1: Global Install (Recommended) - -Install the CLI as a global binary: - -```bash -npm install -g @bradygaster/squad-cli -``` - -Now use it from anywhere: - -```bash -squad init -squad status -squad watch -``` - -### Option 2: One-Off with npx - -Use without installing: - -```bash -npx @bradygaster/squad-cli init -npx @bradygaster/squad-cli status -``` - -### Option 3: Latest from GitHub - -For development or testing, run directly from the GitHub repository: - -```bash -squad init -squad status -``` - -This clones the repo and runs `dist/cli-entry.js` without installing locally. - -## How Resolution Works - -When you type `squad` or `npx @bradygaster/squad-cli`, here's what happens: - -### Global Install (`npm install -g`) - -``` -$ squad init - ↓ -npm looks up 'squad' in global PATH - ↓ -Found: ~/.nvm/versions/node/v20.x/bin/squad (symlink) - ↓ -Resolves to: ~/.nvm/versions/node/v20.x/lib/node_modules/@bradygaster/squad-cli/dist/cli-entry.js - ↓ -Executes: node dist/cli-entry.js ["init"] -``` - -**`cli-entry.js` then:** -1. Parses arguments (`init` → `cmd = 'init'`) -2. Imports SDK: `import { resolveSquad, loadConfig } from '@bradygaster/squad-sdk'` -3. Finds `.squad/` in current directory or parents -4. Loads configuration -5. Executes command - -### npx (No Install) - -``` -$ npx @bradygaster/squad-cli init - ↓ -npx fetches @bradygaster/squad-cli@latest from npm - ↓ -Extracts to ~/.npm/_npx/XXXXX/ - ↓ -Executes: node .../dist/cli-entry.js ["init"] -``` - -Same execution flow as global install, but no persistent disk footprint. - -### GitHub Native (Legacy — no longer supported) - -``` -$ squad init - ↓ -npx resolves @bradygaster/squad-cli from npm registry - ↓ -npm install (cached) - ↓ -npm run build - ↓ -node dist/cli-entry.js ["init"] -``` - -**Why use this:** Bleeding-edge commits, before they're published to npm. Requires build time. - -## Personal Squad: `squad init --global` - -A "personal squad" is a global `.squad/` directory in your home directory, shared across all projects. - -### Setup - -```bash -squad init --global -``` - -**What happens:** -1. Creates `~/.squad/` (Unix/Mac) or `%USERPROFILE%\.squad\` (Windows) -2. Scaffolds standard team structure -3. Sets up agents that can be inherited by project squads - -### Use Cases - -- **Shared agent definitions** across projects -- **Common skills and practices** at the personal level -- **Persistent history** that carries across repos -- **Consistent casting** — same agent names/universes everywhere - -### Example Workflow - -```bash -# 1. Set up personal squad (one-time) -squad init --global - -# 2. Create a personal upstream practice doc -mkdir ~/.squad/skills/personal-guidelines -echo "# My Python conventions..." > ~/.squad/skills/personal-guidelines/SKILL.md - -# 3. In a project, inherit from personal squad -cd ~/my-project -squad upstream add ~/.squad --name personal - -# 4. Now all agents in this project inherit from personal squad -squad # launch shell -> status -# Output: "Inherited skills from: personal" -``` - -### Global vs. Local Squad - -| Aspect | Global (`~/.squad/`) | Local (`./.squad/`) | -|--------|-----|-----| -| **Created by** | `squad init --global` | `squad init` | -| **Scope** | All projects on this machine | Single project | -| **Inheritance** | Can be upstream for local squads | Can inherit from global | -| **History** | Persistent across projects | Per-project learning | -| **Shared agents** | Yes (optional setup) | No | -| **Used when** | No `.squad/` in project + parents | Found in project hierarchy | - -### Resolution Order - -When Squad starts, it looks for `.squad/` in this order: - -1. Current directory (`./.squad/`) -2. Parent directories (walk up to project root) -3. Home directory (`~/.squad/`) -4. Global `@bradygaster/squad-cli` default (fallback only) - -**First match wins.** If you're in a project with `.squad/`, the global `~/.squad/` is ignored (but can be an upstream). - -## Commands at a Glance - -All work with global or npx installations: - -| Command | Global | npx | Needs .squad/ | -|---------|--------|-----|-------| -| `squad init` | ✅ | ✅ | No | -| `squad init --global` | ✅ | ✅ | No | -| `squad status` | ✅ | ✅ | Yes | -| `squad upgrade` | ✅ | ✅ | Yes | -| `squad watch` | ✅ | ✅ | Yes | -| `squad upstream add` | ✅ | ✅ | Yes | -| `squad export` | ✅ | ✅ | Yes | -| `squad import` | ✅ | ✅ | No | - -## Advanced: Which Installation to Use? - -### Use Global Install If... - -- You run Squad regularly in multiple projects -- You want fast startup time -- You want bash/shell completion (future feature) -- You're on a team and everyone has the same version - -**Install:** `npm install -g @bradygaster/squad-cli` - -**Update:** `npm install -g @bradygaster/squad-cli@latest` - -### Use npx If... - -- You want zero disk footprint -- You're running Squad in a CI/CD pipeline -- You want `@latest` without version management -- You're testing a specific version temporarily - -**Usage:** `npx @bradygaster/squad-cli init` - -### Use GitHub Native If... - -- You're a contributor or early tester -- You need unreleased features -- You're debugging a specific commit - -**Usage:** `squad init` - -**Note:** Slower (clones and builds), requires build tools. - -## Troubleshooting - -### "squad: command not found" - -**Cause:** CLI not installed globally, or npm bin not in PATH - -**Fix:** -```bash -# Check if installed -npm list -g @bradygaster/squad-cli - -# If missing: -npm install -g @bradygaster/squad-cli - -# If installed but still "not found", check PATH: -echo $PATH | grep npm # Unix/Mac -echo %PATH% | find npm # Windows (use PowerShell or cmd) - -# Add npm bin to PATH if missing (usually done by Node installer) -# For nvm: nvm use {version} -``` - -### "Cannot find .squad/ directory" - -**Cause:** No squad in current directory or parents - -**Fix:** -```bash -# Create one in current directory: -squad init - -# Or use global squad: -squad init --global -# Then projects will inherit from ~/.squad/ -``` - -### "npm ERR! code E403" when installing globally - -**Cause:** Permissions issue or private package - -**Fix:** -```bash -# Use npx instead (no install): -npx @bradygaster/squad-cli init - -# Or use sudo (not recommended, but works): -sudo npm install -g @bradygaster/squad-cli - -# Or change npm default dir: -mkdir ~/.npm-global -npm config set prefix '~/.npm-global' -export PATH=~/.npm-global/bin:$PATH -npm install -g @bradygaster/squad-cli -``` - -### "Version mismatch" errors when using SDK - -**Cause:** Global CLI version doesn't match installed SDK - -**Fix:** -```bash -# Update both to latest -npm install -g @bradygaster/squad-cli@latest -npm install @bradygaster/squad-sdk@latest # in your project -``` - -### Using squad with Docker or containers - -```dockerfile -FROM node:20 - -# Install CLI globally in image -RUN npm install -g @bradygaster/squad-cli - -# Or use npx (no install): -RUN npx @bradygaster/squad-cli init -``` - -## Version Management - -### Check Installed Version - -```bash -squad --version -``` - -### Update to Latest - -```bash -npm install -g @bradygaster/squad-cli@latest -``` - -### Pin to Specific Version - -```bash -npm install -g @bradygaster/squad-cli@1.2.3 -``` - -### Update Frequency - -- **Stable:** ~monthly releases (minor + patch) -- **Insider:** Push to `insider` branch, install with `@insider` tag - -```bash -npm install -g @bradygaster/squad-cli@insider -``` - -## Next Steps - -- **Getting Started:** See [README](../../README.md) for your first squad -- **Command Reference:** See individual command docs in `docs/guide/` -- **SDK API:** See [SDK Reference](../reference/sdk.md) to understand the programmatic API diff --git a/docs/cli/shell.md b/docs/cli/shell.md deleted file mode 100644 index 956f2cf55..000000000 --- a/docs/cli/shell.md +++ /dev/null @@ -1,516 +0,0 @@ -# Interactive Shell Guide - -> **⚠️ Experimental:** Squad CLI is under active development. APIs and file formats may change between versions. We'd love your feedback — if something isn't working as expected, please [file a bug report](https://github.com/bradygaster/squad/issues/new). - -The Squad interactive shell gives you a persistent connection to your team. Instead of spawning short-lived CLI invocations, the shell maintains a real-time session where you can talk to agents, issue commands, and watch work happen. - ---- - -## Getting Started - -### Enter the Shell - -```bash -squad -``` - -With no arguments, `squad` enters the interactive shell. You'll see a prompt: - -``` -squad > -``` - -### Exit the Shell - -``` -squad > /quit -``` - -Or press **Ctrl+C**. - ---- - -## Shell Commands - -All shell commands start with a forward slash `/`. - -### `/status` — Check team status - -Display the current state of your squad: active agents, sessions, and recent work. - -``` -squad > /status -``` - -Output: -``` -Team Status -──────────────────── -Active Agents: 4/5 - Keaton (lead): idle - McManus (devrel): working (10s) - Verbal (backend): working (25s) - Fenster (tester): idle - Kobayashi (scribe): logging - -Sessions: 5 -Latest decision: "Use React Query for data fetching" (2m ago) -``` - -### `/history` — View recent work - -Display the session log and recent decisions. - -``` -squad > /history -``` - -Shows: -- Last 10 completed tasks -- Decisions made in this session -- Agents that have worked -- Full session transcript (searchable) - -### `/agents` — List team members - -Show all agents on the team with their roles, expertise, and knowledge. - -``` -squad > /agents -``` - -Output: -``` -Team Roster -──────────────────── -Keaton (Lead) - Expertise: Architecture, routing, decisions - Last work: 5m ago - Sessions: 12 - -McManus (DevRel) - Expertise: Documentation, messaging, advocacy - Last work: 2m ago - Sessions: 8 - -[... Verbal, Fenster, Kobayashi ...] -``` - -### `/clear` — Clear the screen - -Clears terminal output. Useful when the shell gets cluttered. - -``` -squad > /clear -``` - -### `/help` — Show all commands - -Display this reference. - -``` -squad > /help -``` - -### `/quit` — Exit the shell - -Close the shell and return to your terminal. - -``` -squad > /quit -``` - -### `/sessions` — List saved sessions - -View past shell sessions. Shows the 10 most recent sessions with their ID prefix, timestamp, and message count. - -``` -squad > /sessions -``` - -Output: -``` -Saved Sessions (3 total) - 1. a1b2c3d4 6/15/2026, 2:30:00 PM (12 messages) - 2. e5f6a7b8 6/14/2026, 10:15:00 AM (8 messages) - 3. c9d0e1f2 6/13/2026, 4:45:00 PM (23 messages) - -Use /resume to restore a session. -``` - -### `/resume ` — Restore a past session - -Resume a previous session by providing the first few characters of its ID. The session's full message history is restored into the current shell. - -``` -squad > /resume a1b2 -✓ Restored session a1b2c3d4 (12 messages) -``` - -If no match is found: -``` -squad > /resume xyz -No session found matching "xyz". Try /sessions to list. -``` - -Typical workflow — pick up where you left off: -``` -squad > /sessions -squad > /resume a1b2 -squad > @Keaton, where were we on the auth work? -``` - ---- - -## Addressing Agents - -You can talk to specific agents by name using two syntaxes: - -### Using `@AgentName` - -Direct an agent to do something: - -``` -squad > @Keaton, analyze the architecture of this project -``` - -The shell routes the message to Keaton. Keaton reads it and acts on it. - -### Using Natural Language Comma Syntax - -Same effect: - -``` -squad > Keaton, set up the database schema for user authentication -``` - -Or directly (without the agent name): - -``` -squad > Write a blog post about our new casting system -``` - -When you don't name an agent, the **coordinator** (Keaton by default) routes the task to whoever is best suited. - ---- - -## Message Routing - -### How Messages Get to Agents - -1. **You type a message** → Shell receives it -2. **Coordinator (Keaton) reads it** → Determines which agent(s) can usefully start -3. **Agents launch in parallel** → All applicable agents work simultaneously -4. **Agents write results** → To `.squad/` (decisions, history, skills, etc.) -5. **Shell streams updates** → You see progress in real-time - -### The Coordinator - -Keaton (the Lead) is your coordinator. He: -- Routes incoming tasks to the right agents -- Decides which agents can start in parallel -- Chains follow-up work (if Agent A finishes, does Agent B have work to do?) -- Records team decisions and learnings - -You never talk directly to the coordinator logic—you just talk to Keaton as a person, and he coordinates. - -### Parallel Execution - -When you give a task that multiple agents can handle: - -``` -squad > Build the login page -``` - -The coordinator might spawn: -- McManus (frontend) → building the UI -- Verbal (backend) → setting up auth endpoints -- Fenster (tester) → writing test cases -- Kobayashi (scribe) → logging everything - -All at once. All in parallel. - ---- - -## Session Management - -### What Is a Session? - -Each agent gets a **persistent session** — a long-lived context where it remembers: -- The task you gave it -- What it's already written to disk -- Previous decisions and learnings -- Its own knowledge base (charter, history) - -Sessions survive crashes. If an agent dies mid-work, it resumes from the exact checkpoint. - -### Viewing Session History - -``` -squad > /history -``` - -Shows full session log with: -- Start time, end time, duration -- What the agent did -- Files written -- Decisions made -- Any errors or blocks - -### Resuming Work - -If an agent crashes or times out: - -``` -squad > @Keaton, check on Verbal and resume if needed -``` - -Keaton will check Verbal's session and resume if interrupted. - -### Ending a Session - -Agents end their own sessions when work is complete. You can ask an agent to wrap up: - -``` -squad > @Verbal, finish up and write a summary -``` - ---- - -## Keyboard Shortcuts - -### Command History - -**Up Arrow** / **Down Arrow** — Scroll through previous commands - -``` -squad > [up arrow] # Previous command -squad > [up arrow] # Command before that -squad > [down arrow] # Next command -``` - -Useful for re-running similar commands or remembering what you asked before. - -### Line Editing - -- **Ctrl+A** — Jump to start of line -- **Ctrl+E** — Jump to end of line -- **Ctrl+U** — Clear from cursor to start of line -- **Ctrl+K** — Clear from cursor to end of line -- **Ctrl+W** — Delete previous word - -### Exit - -- **Ctrl+C** — Exit the shell (same as `/quit`) - ---- - -## Tips and Tricks - -### Tip 1: Use `/status` before big asks - -Before sending a complex task, check team status: - -``` -squad > /status -squad > @Keaton, set up the CI/CD pipeline -``` - -If agents are already working, you might want to wait. - -### Tip 2: Reference decisions, not details - -Instead of explaining the whole architecture: - -``` -# Don't: -squad > Build the auth system. Use JWT. Refresh tokens every 1 hour... - -# Do: -squad > Build the auth system. See the auth decision in decisions.md. -``` - -Agents read your decisions—they're shortcuts for complex context. - -### Tip 3: Ask Keaton to batch work - -If you have multiple tasks: - -``` -squad > @Keaton, here's what needs doing: -1. Set up database schema -2. Build API endpoints -3. Write tests - -Prioritize and route, please. -``` - -Keaton will decompose, prioritize, and launch agents efficiently. - -### Tip 4: Check `/history` after long waits - -If you step away for an hour: - -``` -squad > /history -``` - -Scroll through what happened. Every decision is logged. Every task is recorded. - -### Tip 5: Name agents explicitly for urgent work - -For critical tasks: - -``` -squad > @Keaton, this is critical: we need the deployment script fixed in the next 15 minutes -``` - -The explicit mention ensures the lead coordinator sees it first. - -### Tip 6: Use your shell session as a workspace - -The shell is your thinking space. You can: -- Ask follow-up questions mid-task (`@McManus, did you finish the form?`) -- Route corrections (`@Frontend, I changed my mind, use Tailwind not Bootstrap`) -- Poll progress (`/status`) -- Review decisions (`/history`) - -All without breaking agents' work. - ---- - -## Advanced Usage - -### Working with Multiple Tasks - -The coordinator queues tasks and parallelizes where possible: - -``` -squad > Write the API spec -squad > Build the React components -squad > Set up the database - -/status # See all three being worked on -``` - -Keaton evaluates dependencies and launches all three (frontend doesn't block backend, etc.). - -### Asking Agents About Their Work - -You can ask any agent about their progress: - -``` -squad > @Verbal, what's left on the auth endpoints? -squad > @McManus, show me what you've written so far -squad > @Fenster, are the tests passing? -``` - -Agents respond with status, file paths, and blockers. - -### Pulling in External Context - -If you have a design or spec file: - -``` -squad > @Frontend, here's the figma link: https://... - -Build the signup flow to match this design. -``` - -Agents can read external references (links, uploaded files, etc.) if you provide them. - -### Custom Agent Chaining - -Instead of asking the coordinator to chain work, you can ask agents to coordinate: - -``` -squad > @Keaton, when Verbal finishes the auth API, have him route testing to Fenster -``` - -Keaton can set up explicit hand-offs. - ---- - -## Troubleshooting - -### Shell Hangs or No Response - -**Problem:** You type a message and nothing happens for 10+ seconds. - -**Why:** The coordinator might be evaluating a complex task, or an agent might be streaming large output. - -**Fix:** Press Ctrl+C to interrupt, then check `/status` to see what's happening. - -### Agent Not Responding - -**Problem:** You ask an agent to do something and they don't start working. - -**Why:** They might be locked out, blocked by dependencies, or not recognized as the right agent for the task. - -**Fix:** Check `/status` and `/history` to see blockers. Then ask Keaton to route explicitly: - -``` -squad > @Keaton, route this task to @Verbal and report any blocks -``` - -### Shell Quit Unexpectedly - -**Problem:** Shell closed without you running `/quit`. - -**Why:** Either you pressed Ctrl+C twice, or there was a fatal error. - -**Fix:** Run `squad` again to restart. Check `.squad/log/` for error context. - -### Lost Command History - -**Problem:** You want to find a command you ran earlier but can't scroll back far enough. - -**Why:** Shell history has a limit (usually 1000 lines). - -**Fix:** Check `/history` which shows the full session log across all commands. - ---- - -## Integration with Your Workflow - -### Using the Shell with VS Code - -1. Open an integrated terminal in VS Code -2. Run `squad` to enter the shell -3. Keep it open in a side panel -4. As you edit code, ask agents to review: `@Fenster, test this component` - -### Using the Shell with GitHub CLI - -```bash -# In one terminal -squad - -# In another -gh issue list -gh pr create - -# In squad shell -squad > @Keaton, here's the issue: [paste issue #] -``` - -### Setting Up for Long Sessions - -For long development sprints: - -1. Start the shell: `squad` -2. List what's to do: `@Keaton, what's the roadmap?` -3. Batch work: `@Keaton, prioritize these 5 issues` -4. Let agents work in parallel -5. Check status periodically: `/status` -6. Review decisions: `/history` -7. Ask follow-ups without restarting - ---- - -## See Also - -- **README.md** — Interactive Shell section (quick reference) -- **.squad/decisions.md** — Team decisions (agents read this) -- **.squad/agents/ — Agent charters and history (how agents work) -- **docs/api/** — Programmable SDK reference (for code-level orchestration) diff --git a/docs/cli/vscode.md b/docs/cli/vscode.md deleted file mode 100644 index c670e72a7..000000000 --- a/docs/cli/vscode.md +++ /dev/null @@ -1,406 +0,0 @@ -# SquadUI Integration Guide - -> **⚠️ Experimental:** Squad CLI is under active development. APIs and file formats may change between versions. We'd love your feedback — if something isn't working as expected, please [file a bug report](https://github.com/bradygaster/squad/issues/new). - -This guide explains how Squad works in VS Code (SquadUI), what extension developers need to know, and how the SDK adapts behavior based on the client context. - -## How Squad Works in VS Code - -### User Interaction Flow - -``` -User opens VS Code - ↓ -Opens Squad agent panel (SquadUI extension) - ↓ -Selects agent or team - ↓ -SquadUI calls SDK: runSubagent({ agentName, task, context }) - ↓ -SDK spawns agent session via Copilot SDK - ↓ -Agent executes within VS Code editor context - ↓ -Agent can: - - Read open files (via SDK file APIs) - - Insert code snippets - - Suggest refactors - - Post comments - ↓ -Response streams back to VS Code panel - ↓ -User can accept, reject, or iterate -``` - -## Client Compatibility: CLI Mode vs. VS Code Mode - -Squad adapts its behavior based on which client is running it: - -### CLI Mode (User runs `squad` command) - -```typescript -// Environment -process.env.SQUAD_CLIENT = 'cli' // OR: not set (defaults to CLI) -process.env.TERM = 'xterm-256color' // Terminal available - -// What's available -- Interactive shell (Ink UI) -- Full filesystem access -- stdin/stdout streaming -- Process exit control -``` - -**SDK behavior in CLI mode:** -- Interactive prompts for choices -- Streaming output to stdout -- Can call `process.exit()` -- Full file read/write - -### VS Code Mode (User opens SquadUI extension) - -```typescript -// Environment -process.env.SQUAD_CLIENT = 'vscode' // Set by SquadUI -process.env.TERM = undefined // No terminal - -// What's available -- VS Code editor context -- Open file list -- Selection/cursor position -- Editor commands (insert, replace, etc.) -``` - -**SDK behavior in VS Code mode:** -- No interactive prompts -- Structured responses (JSON-like) -- **Never calls `process.exit()`** (would crash extension) -- File operations scoped to editor context - -## Extension Developer Checklist - -### 1. Detect Client Mode - -Before calling Squad APIs, check which client you're running in: - -```typescript -// In SquadUI extension code -const isVSCodeMode = process.env.SQUAD_CLIENT === 'vscode'; - -if (!isVSCodeMode) { - console.warn('SquadUI should only run in VS Code'); - return; -} -``` - -### 2. Import SDK Safely - -**DO:** Import specific types and functions -```typescript -import type { CastMember, AgentCharter } from '@bradygaster/squad-sdk'; -import { loadConfig, resolveSquad } from '@bradygaster/squad-sdk'; -``` - -**DON'T:** Import the CLI entry point -```typescript -// WRONG: This will call process.exit() and crash your extension -import { main } from '@bradygaster/squad-cli/dist/cli-entry.js'; -``` - -### 3. Load Squad Configuration Safely - -```typescript -import { loadConfig, resolveSquad } from '@bradygaster/squad-sdk'; - -try { - const squadPath = resolveSquad(workspaceRoot); - const config = await loadConfig(squadPath); - - console.log('Squad loaded:', config.team.name); -} catch (err) { - // Handle gracefully — Squad may not be initialized - console.warn('Squad not found:', err.message); - return; -} -``` - -### 4. Call Agents (SDK Pattern) - -Once config is loaded, spawn agents: - -```typescript -import { SquadCoordinator } from '@bradygaster/squad-sdk'; - -const coordinator = new SquadCoordinator({ - teamRoot: squadPath, -}); - -await coordinator.initialize(); - -// Route user task to an agent -const decision = await coordinator.route('refactor this function'); -// decision.agents: ['lead'] or ['backend', 'tester'] -// decision.tier: 'direct' | 'standard' | 'full' - -await coordinator.execute(decision, 'refactor this function'); -``` - -### 5. Stream Responses - -Responses can be long. Use streaming: - -```typescript -import { startStreaming } from '@bradygaster/squad-sdk'; - -const stream = await startStreaming(agentResponse); - -for await (const chunk of stream) { - vscodePanel.append(chunk); // Incremental UI update -} -``` - -### 6. Handle Errors Gracefully - -**DO:** -```typescript -try { - const result = await coordinator.route(userTask); -} catch (err) { - vscode.window.showErrorMessage(`Squad error: ${err.message}`); - telemetry.recordException(err); -} -``` - -**DON'T:** -```typescript -// WRONG: Never call process.exit() in an extension -if (error) process.exit(1); // Crashes VS Code! - -// WRONG: Never throw unhandled errors -throw new Error('something failed'); // Unhandled promise rejection -``` - -### 7. Respect User Context - -Pass editor context to agents: - -```typescript -const editor = vscode.window.activeTextEditor; - -const decision = await coordinator.route(userTask, { - fileContent: editor.document.getText(), - fileName: editor.document.fileName, - selection: editor.selection, - language: editor.document.languageId, -}); -``` - -This lets agents see what you're editing and provide relevant suggestions. - -## API Reference for Extension Developers - -### Core Types - -```typescript -// Agent persona -interface CastMember { - name: string; - role: string; - universe: string; - displayName: string; -} - -// Agent configuration -interface AgentCharter { - identity: { - name: string; - role: string; - expertise: string; - style: string; - }; - knowledge: string; - tools: string[]; - collaboration: string; -} - -// Routing decision -interface RoutingDecision { - tier: 'direct' | 'lightweight' | 'standard' | 'full'; - agents: string[]; - parallel: boolean; - rationale: string; -} - -// Configuration -interface ConfigLoadResult { - team: { name: string; root: string; description?: string }; - agents?: Record; - routing?: RoutingRules; - models?: ModelConfig; -} -``` - -### Key Functions - -```typescript -// Resolve squad location -export function resolveSquad(startPath?: string): string; -export function resolveGlobalSquadPath(): string; - -// Load configuration -export async function loadConfig(squadPath: string): Promise; -export function loadConfigSync(squadPath: string): ConfigLoadResult; - -// Routing -export async function route(message: string): Promise; - -// Response tier selection -export function selectResponseTier(context: TierContext): TierName; - -// Streaming -export function startStreaming(response: unknown): AsyncIterable; -``` - -## Safe Patterns for SquadUI - -### Pattern 1: Read-Only Agent Status - -```typescript -async function getSquadStatus(workspaceRoot: string) { - const squadPath = resolveSquad(workspaceRoot); - const config = await loadConfig(squadPath); - - return { - team: config.team.name, - agents: Object.keys(config.agents || {}), - status: 'ready', - }; -} -``` - -**Safe:** No mutations, no process calls. - -### Pattern 2: Non-Blocking Agent Spawn - -```typescript -async function spawnAgentNonBlocking( - workspaceRoot: string, - agentName: string, - task: string -) { - const squadPath = resolveSquad(workspaceRoot); - const config = await loadConfig(squadPath); - - // Validate agent exists - if (!config.agents?.[agentName]) { - throw new Error(`Agent ${agentName} not found`); - } - - // Spawn (returns immediately, agent runs in background) - const sessionId = crypto.randomUUID(); - - // TODO: Integrate with SDK session pool when available - - return { sessionId, agentName, status: 'spawned' }; -} -``` - -**Safe:** Validates input before calling SDK, handles missing agents. - -### Pattern 3: Stream Agent Output to VS Code - -```typescript -async function* streamAgentOutput( - workspaceRoot: string, - agentName: string, - task: string -): AsyncGenerator { - const squadPath = resolveSquad(workspaceRoot); - const coordinator = new SquadCoordinator({ teamRoot: squadPath }); - - await coordinator.initialize(); - - try { - const decision = await coordinator.route(task); - - // Stream back to caller (SquadUI panel) - yield `Routing to: ${decision.agents.join(', ')}\n`; - - // TODO: Wire agent response stream when session API available - - } finally { - await coordinator.shutdown(); - } -} -``` - -**Safe:** Proper cleanup via shutdown(), respects async iteration. - -## Troubleshooting - -### "Squad not found" - -**Cause:** No `.squad/` in workspace or parents - -**Fix:** -```typescript -try { - const squadPath = resolveSquad(workspaceFolder.uri.fsPath); -} catch (err) { - vscode.window.showInformationMessage( - 'No Squad found. Run `squad init` to get started.', - 'Run Squad Init' - ).then(() => { - vscode.commands.executeCommand('squad.init'); - }); -} -``` - -### "process.exit() called inside extension" - -**Cause:** Imported CLI entry point by mistake - -**Fix:** Only import from `@bradygaster/squad-sdk`, not `@bradygaster/squad-cli/dist/cli-entry.js` - -```typescript -// ✅ SAFE -import { resolveSquad } from '@bradygaster/squad-sdk'; - -// ❌ UNSAFE -import { main } from '@bradygaster/squad-cli/dist/cli-entry'; -``` - -### Agent response not streaming - -**Cause:** Not using streaming API - -**Fix:** -```typescript -// Instead of awaiting full response: -const response = await agent.run(task); // Waits for completion - -// Use streaming: -for await (const chunk of agent.stream(task)) { - uiPanel.append(chunk); // Incremental updates -} -``` - -### Type errors with agent types - -**Cause:** Importing from wrong module - -**Fix:** -```typescript -// ✅ CORRECT -import type { AgentCharter, CastMember } from '@bradygaster/squad-sdk'; - -// ❌ INCORRECT -import type { AgentCharter } from '@bradygaster/squad-sdk/agents'; // Wrong path -``` - -Use the barrel export from `@bradygaster/squad-sdk`. - -## Next Steps - -- **SDK API:** See [SDK Reference](../reference/sdk.md) to understand SDK modules -- **SDK Reference:** See [SDK Reference](../reference/sdk.md) for all public exports -- **Example Extension:** Check the Squad team's SquadUI extension source for reference implementation diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 470ceebad..000000000 --- a/docs/index.md +++ /dev/null @@ -1,74 +0,0 @@ -# Squad — Your AI Development Team - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -**Describe what you're building. Get a team of specialists that live in your repo.** - -Squad is a multi-agent runtime for GitHub Copilot. You talk to your team in plain English — they fan out, build in parallel, and land pull requests in minutes. - ---- - -## Try this: - -Open Copilot and select Squad. Then type: - -``` -Team, build the recipe listing page. We need an API endpoint that -returns recipes and a React component that displays them. -``` - -Here's what happens: - -``` -🏗️ Hicks — reviewing requirements, defining API contract -⚛️ Ripley — building RecipeList component -🔧 Dallas — creating GET /api/recipes endpoint -🧪 Lambert — writing test cases from requirements -📋 Scribe — logging decisions -``` - -Five agents, working at the same time. The tester writes tests *while* the code is being built. Results land in minutes, not hours. - ---- - -## Why Squad? - -🚀 **Parallel AI teamwork** — Give a task to the team and multiple agents fan out simultaneously. No waiting in line. - -🧠 **Persistent memory** — Agents remember decisions and conventions across sessions. Your team gets smarter every time. - -🐙 **GitHub-native** — Squad lives in your repo as `.squad/`. Commit it, share it, clone it. Your team travels with your code. - ---- - -## → [Get Started](get-started/installation.md) - -Install Squad in under a minute and run your first session. - ---- - -## What's Inside - -| Section | What you'll find | -|---------|-----------------| -| [Installation](get-started/installation.md) | Get running in 60 seconds | -| [Your First Session](get-started/first-session.md) | From zero to fan-out — the walkthrough | -| [Features](features/team-setup.md) | Everything Squad can do — parallel work, memory, routing, and more | -| [Guide](guide/tips-and-tricks.md) | Tips, prompts, and patterns that work | -| [CLI Reference](reference/cli.md) | Commands, shell, config files | -| [SDK Reference](reference/sdk.md) | Programmatic API | -| [Config Reference](reference/config.md) | squad.config.ts, .squad/ structure, models | -| [Scenarios](scenarios/existing-repo.md) | Real-world patterns for your project | -| [What's New](whatsnew.md) | Release history | - ---- - -## Quick Links - -- 💬 [Discussions & Support](https://github.com/bradygaster/squad/discussions) -- 📦 [npm — @bradygaster/squad-cli](https://www.npmjs.com/package/@bradygaster/squad-cli) -- 📦 [npm — @bradygaster/squad-sdk](https://www.npmjs.com/package/@bradygaster/squad-sdk) -- 🔗 [GitHub Repository](https://github.com/bradygaster/squad) - -**Ready?** → [Install Squad](get-started/installation.md) diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 000000000..e879ed4bc --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,6580 @@ +{ + "name": "squad-docs", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "squad-docs", + "version": "0.0.1", + "dependencies": { + "@tailwindcss/vite": "^4.1.0", + "astro": "^5.7.0", + "sharp": "^0.33.0", + "tailwindcss": "^4.1.0" + } + }, + "node_modules/@astrojs/compiler": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz", + "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==", + "license": "MIT" + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.5.tgz", + "integrity": "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==", + "license": "MIT" + }, + "node_modules/@astrojs/markdown-remark": { + "version": "6.3.10", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.10.tgz", + "integrity": "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.7.5", + "@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.19.0", + "smol-toml": "^1.5.2", + "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" + } + }, + "node_modules/@astrojs/prism": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", + "integrity": "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + } + }, + "node_modules/@astrojs/telemetry": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", + "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.0.tgz", + "integrity": "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", + "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.31.1", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", + "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-x64": "4.2.1", + "@tailwindcss/oxide-freebsd-x64": "4.2.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-x64-musl": "4.2.1", + "@tailwindcss/oxide-wasm32-wasi": "4.2.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", + "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", + "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", + "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", + "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", + "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", + "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", + "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", + "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", + "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", + "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", + "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", + "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.1", + "@tailwindcss/oxide": "4.2.1", + "tailwindcss": "4.2.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/astro": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.0.tgz", + "integrity": "sha512-CHiohwJIS4L0G6/IzE1Fx3dgWqXBCXus/od0eGUfxrZJD2um2pE7ehclMmgL/fXqbU7NfE1Ze2pq34h2QaA6iQ==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.13.0", + "@astrojs/internal-helpers": "0.7.5", + "@astrojs/markdown-remark": "6.3.10", + "@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" + }, + "bin": { + "astro": "astro.js" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.34.0" + } + }, + "node_modules/astro/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/astro/node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/astro/node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "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" + } + }, + "node_modules/astro/node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "license": "MIT", + "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" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/astro/node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "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" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "license": "ISC" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie-es": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", + "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "license": "MIT" + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/deterministic-object-hash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", + "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", + "license": "MIT", + "dependencies": { + "base-64": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/devalue": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", + "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/fontace": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.2" + } + }, + "node_modules/fontkitten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", + "license": "MIT", + "dependencies": { + "tiny-inflate": "^1.0.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/h3": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.5.tgz", + "integrity": "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.2", + "crossws": "^0.3.5", + "defu": "^6.1.4", + "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" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-definitions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-mock-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", + "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", + "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/p-limit": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", + "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "license": "MIT" + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/rehype": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-smartypants": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "license": "MIT", + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sax": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", + "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", + "license": "MIT", + "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" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/smol-toml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz", + "integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/svgo": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", + "license": "MIT", + "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": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, + "node_modules/ultrahtml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", + "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", + "license": "MIT" + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unifont": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", + "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "ofetch": "^1.5.1", + "ohash": "^2.0.11" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unstorage": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.4.tgz", + "integrity": "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.5", + "lru-cache": "^11.2.0", + "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" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz", + "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "license": "MIT", + "dependencies": { + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", + "license": "MIT" + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-spinner": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.3.tgz", + "integrity": "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==", + "license": "MIT", + "dependencies": { + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18.19" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, + "node_modules/zod-to-ts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", + "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", + "peerDependencies": { + "typescript": "^4.9.4 || ^5.0.2", + "zod": "^3" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 000000000..f2fd721aa --- /dev/null +++ b/docs/package.json @@ -0,0 +1,18 @@ +{ + "name": "squad-docs", + "type": "module", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "astro": "^5.7.0", + "tailwindcss": "^4.1.0", + "@tailwindcss/vite": "^4.1.0", + "sharp": "^0.33.0" + } +} diff --git a/docs/sdk/api-reference.md b/docs/sdk/api-reference.md deleted file mode 100644 index 0b4636a6e..000000000 --- a/docs/sdk/api-reference.md +++ /dev/null @@ -1,804 +0,0 @@ -# SDK API Reference - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -Complete reference for all public exports from `@bradygaster/squad-sdk`. Each section includes types, functions, and usage examples. - -## Overview - -Squad SDK exports are organized by domain: - -```typescript -// All imports work from the barrel export: -import { - // Resolution - resolveSquad, resolveGlobalSquadPath, ensureSquadPath, - - // Runtime - MODELS, TIMEOUTS, AGENT_ROLES, - loadConfig, loadConfigSync, - - // Agents - onboardAgent, - - // Casting - CastingEngine, CastingHistory, - - // Coordinator - SquadCoordinator, selectResponseTier, getTier, - - // Tools - defineTool, ToolRegistry, - - // OTel - initializeOTel, shutdownOTel, getTracer, getMeter, - bridgeEventBusToOTel, createOTelTransport, - initSquadTelemetry, -} from '@bradygaster/squad-sdk'; -``` - ---- - -## Resolution - -**Module:** `resolution.ts` - -Functions to locate Squad directories. - -### `resolveSquad(startPath?: string): string` - -Find `.squad/` directory starting from a path and walking up to the project root. - -```typescript -import { resolveSquad } from '@bradygaster/squad-sdk'; - -// From current directory -const squadPath = resolveSquad(); // → '/home/user/project/.squad' - -// From specific path -const squadPath = resolveSquad('/home/user/project/src'); // → '/home/user/project/.squad' - -// Throws if not found -try { - const squadPath = resolveSquad('/tmp'); // No .squad/ anywhere -} catch (err) { - console.error('Squad not found'); -} -``` - -### `resolveGlobalSquadPath(): string` - -Get path to global personal squad (`~/.squad/` on Unix, `%USERPROFILE%\.squad\` on Windows). - -```typescript -import { resolveGlobalSquadPath } from '@bradygaster/squad-sdk'; - -const globalSquad = resolveGlobalSquadPath(); -// → /home/user/.squad (or C:\Users\user\.squad on Windows) -``` - -### `ensureSquadPath(startPath?: string): string` - -Like `resolveSquad()`, but creates the directory if it doesn't exist. - -```typescript -import { ensureSquadPath } from '@bradygaster/squad-sdk'; - -const squadPath = ensureSquadPath(); // Creates .squad/ if missing -``` - ---- - -## Runtime Constants - -**Module:** `runtime/constants.ts` - -Predefined catalogs for models, timeouts, and agent roles. - -### `MODELS: ModelCatalog` - -All 17 supported models, organized by tier. - -```typescript -import { MODELS } from '@bradygaster/squad-sdk'; - -// Access by tier -MODELS.premium; // ['claude-opus-4.6', 'gpt-5.2', ...] -MODELS.standard; // ['claude-sonnet-4.5', 'gpt-5.1', ...] -MODELS.fast; // ['claude-haiku-4.5', 'gpt-5-mini', ...] - -// Find a model -const model = MODELS.all.find(m => m.name === 'claude-sonnet-4.5'); -console.log(model.tier, model.costPerMToken); -``` - -### `TIMEOUTS: TimeoutConfig` - -Standard timeout values for agent operations. - -```typescript -import { TIMEOUTS } from '@bradygaster/squad-sdk'; - -console.log(TIMEOUTS.agentInitMs); // 30000 (30s) -console.log(TIMEOUTS.agentExecuteMs); // 300000 (5 min) -console.log(TIMEOUTS.coordinatorRouteMs); // 5000 (5s) -``` - -### `AGENT_ROLES: Record` - -Standard agent roles and their default properties. - -```typescript -import { AGENT_ROLES } from '@bradygaster/squad-sdk'; - -console.log(AGENT_ROLES.lead); // { tools: [...], model: 'standard', ... } -console.log(AGENT_ROLES.backend); // { tools: [...], model: 'standard', ... } -console.log(AGENT_ROLES.frontend); // { tools: [...], model: 'standard', ... } -``` - ---- - -## Configuration - -**Module:** `config/*.ts` - -Load and validate Squad configuration. - -### `loadConfig(squadPath: string): Promise` - -Load configuration asynchronously. Reads `squad.config.ts` (if present), parses routing/model overrides, validates schemas. - -```typescript -import { loadConfig } from '@bradygaster/squad-sdk'; - -const config = await loadConfig('./.squad'); - -console.log(config.team.name); // Team name -console.log(Object.keys(config.agents)); // Agent names -console.log(config.routing.workTypes); // Routing rules -``` - -**Types:** - -```typescript -interface ConfigLoadResult { - team: { - name: string; - root: string; - description?: string; - }; - agents?: Record; - routing?: RoutingConfig; - models?: ModelConfig; -} - -interface AgentConfig { - role: string; - model?: string; - tools?: string[]; - status?: 'active' | 'inactive'; -} - -interface RoutingConfig { - workTypes: RoutingRule[]; - issueLabels?: IssueRoutingRule[]; -} - -interface RoutingRule { - pattern: RegExp; - targets: string[]; - tier?: ResponseTier; -} -``` - -### `loadConfigSync(squadPath: string): ConfigLoadResult` - -Synchronous version of `loadConfig()`. Useful when you can't use async/await. - -```typescript -import { loadConfigSync } from '@bradygaster/squad-sdk'; - -const config = loadConfigSync('./.squad'); -``` - ---- - -## Agents & Onboarding - -**Module:** `agents/onboarding.ts` - -Create and configure agents at runtime. - -### `onboardAgent(options: OnboardOptions): Promise` - -Create a new agent directory, charter, and history file. - -```typescript -import { onboardAgent } from '@bradygaster/squad-sdk'; - -const result = await onboardAgent({ - teamRoot: './.squad', - agentName: 'data-analyst', - role: 'backend', - displayName: 'Dana — Data Analyst', - projectContext: 'A recipe sharing app with PostgreSQL and React', - userName: 'Alice', -}); - -console.log(result.agentDir); // './.squad/agents/data-analyst' -console.log(result.charterPath); // './.squad/agents/data-analyst/charter.md' -console.log(result.historyPath); // './.squad/agents/data-analyst/history.md' -console.log(result.createdFiles); // All files created -``` - -**Types:** - -```typescript -interface OnboardOptions { - teamRoot: string; - agentName: string; - role: string; - displayName?: string; - projectContext?: string; - userName?: string; - charterTemplate?: string; -} - -interface OnboardResult { - createdFiles: string[]; - agentDir: string; - charterPath: string; - historyPath: string; -} -``` - ---- - -## Casting - -**Module:** `casting/index.ts` - -Generate and track agent personas. - -### `CastingEngine` - -Runtime engine that generates agent personas from universe themes. - -```typescript -import { CastingEngine, type CastingConfig } from '@bradygaster/squad-sdk'; - -const engine = new CastingEngine({ - universes: ['The Wire', 'Seinfeld'], - activeUniverse: 'The Wire', -}); - -const members = await engine.castTeam([ - { role: 'lead', title: 'Lead Developer' }, - { role: 'backend', title: 'Backend Engineer' }, -]); - -console.log(members[0].name); // e.g., 'Stringer' (from The Wire) -console.log(members[0].universe); // 'The Wire' -console.log(members[0].role); // 'lead' -``` - -### `CastingHistory` - -Track all casting decisions over time. - -```typescript -import { CastingHistory, type CastingRecord } from '@bradygaster/squad-sdk'; - -const history = new CastingHistory('./.squad/casting'); - -// Get all castings for an agent -const records = history.getRecordsByAgent('lead'); - -// Check if a name was used in a previous session -const previousCast = history.findByName('Stringer'); -``` - -**Types:** - -```typescript -interface CastMember { - name: string; - role: string; - universe: string; - displayName: string; -} - -interface CastingRecord { - sessionId: string; - timestamp: Date; - members: CastingRecord Member[]; -} - -interface CastingRecordMember extends CastMember { - confidence: 'low' | 'medium' | 'high'; -} -``` - ---- - -## Coordinator - -**Module:** `coordinator/index.ts` - -Central routing and orchestration engine. - -### `SquadCoordinator` - -Main class for routing work to agents. - -```typescript -import { SquadCoordinator } from '@bradygaster/squad-sdk'; - -const coordinator = new SquadCoordinator({ - teamRoot: './.squad', - enableParallel: true, -}); - -await coordinator.initialize(); - -// Route a message -const decision = await coordinator.route('refactor the API'); - -console.log(decision.tier); // 'standard' or 'full' -console.log(decision.agents); // ['backend', 'tester'] -console.log(decision.parallel); // true if multi-agent -console.log(decision.rationale); // Explanation of routing choice - -// Execute the decision -await coordinator.execute(decision, 'refactor the API'); - -// Cleanup -await coordinator.shutdown(); -``` - -**Types:** - -```typescript -interface RoutingDecision { - tier: ResponseTier; - agents: string[]; - parallel: boolean; - rationale: string; -} - -type ResponseTier = 'direct' | 'lightweight' | 'standard' | 'full'; -``` - -### `selectResponseTier(context: TierContext): TierName` - -Choose the right response tier for a task. - -```typescript -import { selectResponseTier } from '@bradygaster/squad-sdk'; - -const tier = selectResponseTier({ - complexity: 'high', - budget: 10, // max tokens (thousands) - userTeam: true, // team task vs. personal -}); - -console.log(tier); // 'standard' or 'full' -``` - -### `getTier(name: TierName): TierDefinition` - -Get configuration for a specific tier. - -```typescript -import { getTier } from '@bradygaster/squad-sdk'; - -const tier = getTier('standard'); -console.log(tier.maxAgents); // Max parallel agents -console.log(tier.defaultModel); // Default model for this tier -console.log(tier.toolset); // Available tools -``` - ---- - -## Tools - -**Module:** `tools/index.ts` - -Define custom tools and access the built-in tool registry. - -### `defineTool(config: ToolConfig): SquadTool` - -Define a new tool with typed parameters. - -```typescript -import { defineTool, type ToolResult } from '@bradygaster/squad-sdk'; - -const myTool = defineTool<{ query: string }>({ - name: 'search_docs', - description: 'Search project documentation', - parameters: { - type: 'object', - properties: { - query: { type: 'string', description: 'Search query' }, - }, - required: ['query'], - }, - handler: async (args) => { - const results = await searchDocs(args.query); - return { - textResultForLlm: `Found ${results.length} results`, - resultType: 'success', - toolTelemetry: { resultCount: results.length }, - }; - }, -}); -``` - -**Types:** - -```typescript -interface ToolConfig { - name: string; - description: string; - parameters: Record; // JSON schema - handler: (args: TArgs) => Promise | SquadToolResult; - agentName?: string; -} - -interface SquadToolResult { - textResultForLlm: string; - resultType: 'success' | 'failure' | 'unknown'; - error?: string; - toolTelemetry?: Record; -} -``` - -### `ToolRegistry` - -Access and manage the built-in tool set. - -```typescript -import { ToolRegistry } from '@bradygaster/squad-sdk'; - -const registry = new ToolRegistry('./.squad'); - -// Get all tools -const tools = registry.getTools(); - -// Get tools for a specific agent -const agentTools = registry.getToolsForAgent(['squad_route', 'squad_decide']); - -// Look up a tool -const routeTool = registry.getTool('squad_route'); -``` - -**Built-in tools:** - -| Tool | Purpose | -|------|---------| -| `squad_route` | Route a task to another agent | -| `squad_decide` | Write decisions to the inbox | -| `squad_memory` | Append to agent history | -| `squad_status` | Query session pool state | -| `squad_skill` | Read/write agent skills | - ---- - -## Observability (OpenTelemetry) - -**Module:** `runtime/otel*.ts` - -Three-layer observability API for traces, metrics, and telemetry. - -### Layer 1: Low-Level Control - -#### `initializeOTel(config?: OTelConfig): Promise` - -Initialize OTel providers (TracerProvider, MeterProvider) with OTLP HTTP exporters. - -```typescript -import { initializeOTel } from '@bradygaster/squad-sdk'; - -await initializeOTel({ - endpoint: 'http://localhost:4318', - serviceName: 'my-squad', - debug: true, -}); -``` - -#### `shutdownOTel(): Promise` - -Flush pending traces and metrics, shut down providers. - -```typescript -import { shutdownOTel } from '@bradygaster/squad-sdk'; - -await shutdownOTel(); -``` - -#### `getTracer(name: string): Tracer` - -Get a tracer instance for creating spans. - -```typescript -import { getTracer } from '@bradygaster/squad-sdk'; -import { SpanStatusCode } from '@opentelemetry/api'; - -const tracer = getTracer('my-component'); - -const span = tracer.startSpan('my-work', { - attributes: { 'component': 'auth', 'user.id': '123' }, -}); - -try { - // Do work -} catch (err) { - span.setStatus({ code: SpanStatusCode.ERROR, message: err.message }); - span.recordException(err); -} finally { - span.end(); -} -``` - -#### `getMeter(name: string): Meter` - -Get a meter instance for recording metrics. - -```typescript -import { getMeter } from '@bradygaster/squad-sdk'; - -const meter = getMeter('my-component'); - -const counter = meter.createCounter('requests_total'); -counter.add(1, { 'method': 'GET', 'status': '200' }); -``` - -**Type:** - -```typescript -interface OTelConfig { - endpoint?: string; // OTLP HTTP endpoint (e.g., http://localhost:4318) - serviceName?: string; // Service name for traces (default: 'squad-sdk') - debug?: boolean; // Enable debug logging -} -``` - -### Layer 2: Mid-Level Bridge - -#### `bridgeEventBusToOTel(bus: EventBus): UnsubscribeFn` - -Automatically forward all EventBus events as OTel spans. - -```typescript -import { bridgeEventBusToOTel } from '@bradygaster/squad-sdk'; - -const unsubscribe = bridgeEventBusToOTel(eventBus); - -// Later, clean up: -unsubscribe(); -``` - -#### `createOTelTransport(): TelemetryTransport` - -Create a telemetry transport backed by OTel. - -```typescript -import { createOTelTransport, setTelemetryTransport } from '@bradygaster/squad-sdk'; - -const transport = createOTelTransport(); -setTelemetryTransport(transport); -``` - -### Layer 3: High-Level Convenience - -#### `initSquadTelemetry(options: SquadTelemetryOptions): Promise` - -One-call setup that configures OTel, wires the EventBus bridge, and registers the TelemetryTransport. - -```typescript -import { initSquadTelemetry } from '@bradygaster/squad-sdk'; - -const telemetry = await initSquadTelemetry({ - endpoint: 'http://localhost:4318', - serviceName: 'my-squad', - eventBus: myEventBus, - installTransport: true, // default -}); - -console.log('Tracing:', telemetry.tracing); // boolean -console.log('Metrics:', telemetry.metrics); // boolean - -// Later: -await telemetry.shutdown(); -``` - -**Types:** - -```typescript -interface SquadTelemetryOptions extends OTelConfig { - eventBus?: EventBus; - installTransport?: boolean; // default: true -} - -interface SquadTelemetryHandle { - tracing: boolean; - metrics: boolean; - shutdown(): Promise; -} -``` - ---- - -## Streaming - -**Module:** `runtime/streaming.ts` - -Handle streamed agent responses. - -### `createReadableStream(response: unknown): ReadableStream` - -Convert an agent response to a readable stream. - -```typescript -import { createReadableStream } from '@bradygaster/squad-sdk'; - -const stream = createReadableStream(agentResponse); - -const reader = stream.getReader(); -let result; - -while (!(result = await reader.read()).done) { - console.log(result.value); // Chunk of response -} -``` - ---- - -## Upstream Inheritance - -**Module:** `upstream/index.ts` - -Share practices, skills, and decisions across teams. - -### Types - -```typescript -type UpstreamType = 'local' | 'git' | 'export'; - -interface UpstreamSource { - type: UpstreamType; - location: string; // Path or Git URL - name: string; - ref?: string; // Git branch/tag - lastSync?: Date; -} - -interface UpstreamConfig { - sources: UpstreamSource[]; -} - -interface ResolvedUpstream { - name: string; - skills?: SkillDefinition[]; - decisions?: DecisionEntry[]; - wisdom?: string; - routing?: RoutingRules; - castingPolicy?: CastingPolicy; -} -``` - -### Functions - -#### `readUpstreamConfig(squadPath: string): Promise` - -Load upstream sources from `.squad/upstream.json`. - -```typescript -import { readUpstreamConfig } from '@bradygaster/squad-sdk'; - -const config = await readUpstreamConfig('./.squad'); - -for (const source of config.sources) { - console.log(source.name, source.type, source.location); -} -``` - -#### `resolveUpstreams(config: UpstreamConfig, squadPath: string): Promise` - -Resolve all upstreams and return their inherited content. - -```typescript -import { resolveUpstreams } from '@bradygaster/squad-sdk'; - -const resolved = await resolveUpstreams(config, './.squad'); - -// Merged skills from all upstreams -resolved.forEach(up => { - console.log(`${up.name}: ${up.skills?.length || 0} skills`); -}); -``` - -#### `buildInheritedContextBlock(resolved: ResolvedUpstream[]): string` - -Build a markdown block of all inherited context (for agent charters). - -```typescript -import { buildInheritedContextBlock } from '@bradygaster/squad-sdk'; - -const contextBlock = buildInheritedContextBlock(resolved); -// Use in agent charter as: -// ## Inherited Context -// [contextBlock] -``` - -#### `buildSessionDisplay(resolved: ResolvedUpstream[]): string` - -Build a human-readable display of upstream sources (for `squad status`). - -```typescript -import { buildSessionDisplay } from '@bradygaster/squad-sdk'; - -const display = buildSessionDisplay(resolved); -console.log(display); -// Output: -// Platform (git, last synced 2 days ago) -// - 15 skills -// - 3 decisions -``` - ---- - -## Skills - -**Module:** `skills/index.ts` - -Load and manage agent skills. - -### Functions - -```typescript -export function loadSkills(skillsDir: string): Promise; -export function readSkill(skillPath: string): Promise; -export function writeSkill(skillPath: string, skill: SkillDefinition): Promise; -``` - ---- - -## Glossary of Exports - -| Export | Type | Module | Purpose | -|--------|------|--------|---------| -| `resolveSquad` | function | resolution | Find .squad directory | -| `resolveGlobalSquadPath` | function | resolution | Get ~/.squad path | -| `ensureSquadPath` | function | resolution | Find or create .squad | -| `MODELS` | constant | runtime/constants | Model catalog | -| `TIMEOUTS` | constant | runtime/constants | Standard timeouts | -| `AGENT_ROLES` | constant | runtime/constants | Agent role definitions | -| `loadConfig` | function | config | Async config loading | -| `loadConfigSync` | function | config | Sync config loading | -| `onboardAgent` | function | agents | Create new agent | -| `CastingEngine` | class | casting | Generate personas | -| `CastingHistory` | class | casting | Track castings | -| `SquadCoordinator` | class | coordinator | Route and orchestrate | -| `selectResponseTier` | function | coordinator | Choose response tier | -| `getTier` | function | coordinator | Get tier config | -| `defineTool` | function | tools | Define custom tool | -| `ToolRegistry` | class | tools | Manage tools | -| `initializeOTel` | function | runtime/otel | Init OTel providers | -| `shutdownOTel` | function | runtime/otel | Shutdown OTel | -| `getTracer` | function | runtime/otel | Get tracer | -| `getMeter` | function | runtime/otel | Get meter | -| `bridgeEventBusToOTel` | function | runtime/otel-bridge | EventBus → OTel | -| `createOTelTransport` | function | runtime/otel-bridge | Create OTel transport | -| `initSquadTelemetry` | function | runtime/otel-init | One-call setup | -| `readUpstreamConfig` | function | upstream | Read upstream.json | -| `resolveUpstreams` | function | upstream | Resolve upstreams | -| `buildInheritedContextBlock` | function | upstream | Build context | -| `buildSessionDisplay` | function | upstream | Build UI display | - -## Next Steps - -- **Getting Started:** [Installation](../get-started/installation.md) — Set up Squad with the SDK -- **Features:** [Memory & Knowledge](../concepts/memory-and-knowledge.md) — How agents learn from your project -- **CLI Reference:** [CLI Documentation](../reference/cli.md) — Command-line interface guide diff --git a/docs/sdk/integration.md b/docs/sdk/integration.md deleted file mode 100644 index dd28c9962..000000000 --- a/docs/sdk/integration.md +++ /dev/null @@ -1,89 +0,0 @@ -# SDK Integration Guide - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -**Issue:** #34 (M0-10) - ---- - -## Overview - -This guide covers connecting to the Copilot SDK via Squad's adapter layer, managing sessions, handling events, and recovering from errors. - -## SquadClient Setup - -`SquadClient` wraps `@github/copilot-sdk` with lifecycle management and auto-reconnection. Create a client with typed options: - -```typescript -import { SquadClient } from '@squad/sdk'; - -const client = new SquadClient({ - port: 3000, - auth: { token: process.env.COPILOT_TOKEN }, - reconnection: { maxRetries: 5, backoffMs: 1000 }, -}); - -await client.connect(); -``` - -The client tracks connection state via `SquadConnectionState`: `disconnected → connecting → connected → reconnecting → error`. Auto-reconnection uses exponential backoff with jitter. - -## Session Management - -Use `SquadClientWithPool` for production workloads — it composes `SquadClient`, `SessionPool`, and `EventBus`: - -```typescript -import { SquadClientWithPool } from '@squad/sdk'; - -const squad = new SquadClientWithPool({ - client: clientOptions, - pool: { maxConcurrent: 10, idleTimeout: 60_000 }, -}); - -const session = await squad.createSession({ agent: 'backend' }); -const response = await session.sendMessage('Implement the /users endpoint'); -await session.destroy(); -``` - -`SessionPool` enforces concurrency limits, runs health checks, and reaps idle sessions automatically. `SessionStatus` tracks each session through `creating → active → idle → error → destroyed`. - -## Event Handling - -`EventBus` provides typed pub/sub for session lifecycle events: - -```typescript -squad.events.on('session.created', (event: SquadEvent) => { - console.log(`Session ${event.sessionId} started`); -}); - -squad.events.on('session.status_changed', (event) => { - if (event.payload.status === 'error') { - // handle degraded session - } -}); -``` - -Events include `session.created`, `session.destroyed`, `session.status_changed`, and tool execution events. - -## Error Handling - -All SDK errors are wrapped in `SquadError` subtypes with severity, category, and recoverability: - -```typescript -try { - await client.connect(); -} catch (err) { - if (err instanceof SDKConnectionError) { - // Retryable — client will auto-reconnect - } else if (err instanceof AuthenticationError) { - // Fatal — check credentials - } -} -``` - -Error classes: `SDKConnectionError`, `SessionLifecycleError`, `ToolExecutionError`, `ModelAPIError`, `ConfigurationError`, `AuthenticationError`, `RateLimitError`, `RuntimeError`, `ValidationError`. Use `ErrorFactory` to wrap raw SDK errors with Squad context. - -## Telemetry - -`TelemetryCollector` tracks operation latency and error rates. `HealthMonitor` runs periodic connection checks returning `HealthCheckResult` with status (`healthy | degraded | unhealthy`) and response time. diff --git a/docs/sdk/tools-and-hooks.md b/docs/sdk/tools-and-hooks.md deleted file mode 100644 index 9d5d63a33..000000000 --- a/docs/sdk/tools-and-hooks.md +++ /dev/null @@ -1,95 +0,0 @@ -# Custom Tools & Hooks Guide - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -**Issue:** #35 (M1-13) - ---- - -## Overview - -Squad ships with 5 built-in tools and a hook pipeline for policy enforcement. This guide covers extending both. - -## ToolRegistry API - -`ToolRegistry` manages tool definitions. Each tool has a name, JSON schema, and async handler: - -```typescript -import { ToolRegistry, defineTool } from '@squad/sdk'; - -const registry = new ToolRegistry(); - -const myTool = defineTool({ - name: 'search-docs', - description: 'Search internal documentation', - schema: { - type: 'object', - properties: { - query: { type: 'string', description: 'Search query' }, - }, - required: ['query'], - }, - handler: async (params) => { - const results = await searchIndex(params.query); - return { success: true, data: results }; - }, -}); - -registry.register(myTool); -``` - -The handler returns a `ToolResult` with `success` flag and `data` payload. Built-in tools include: `route` (dispatch to another agent), `decision` (record a team decision), `memory` (agent history), `status` (session pool query), and `skill` (read/write skills). - -## HookPipeline - -`HookPipeline` intercepts tool calls at two points: before execution (`PreToolUseHook`) and after (`PostToolUseHook`). Hooks return a `HookAction`: `allow`, `block`, or `modify`. - -```typescript -import { HookPipeline, PreToolUseHook } from '@squad/sdk'; - -const auditHook: PreToolUseHook = async (toolName, params, context) => { - console.log(`Agent ${context.agentId} calling ${toolName}`); - return { action: 'allow' }; -}; - -const pipeline = new HookPipeline(); -pipeline.addPreHook(auditHook); -``` - -## Writing Custom Hooks - -Custom hooks receive the tool name, parameters, and agent context. Use them for logging, validation, or transformation: - -```typescript -const sanitizeHook: PreToolUseHook = async (toolName, params, context) => { - if (toolName === 'shell' && params.command.includes('rm -rf')) { - return { action: 'block', reason: 'Destructive command blocked' }; - } - return { action: 'allow' }; -}; -``` - -Post-tool hooks inspect results and can trigger follow-up actions like notifications or audit logging. - -## Built-in Policies - -Squad ships 5 policies configured via `PolicyConfig`: - -1. **ReviewerLockoutHook** — Agents cannot edit files they are reviewing -2. **File guards** — Restrict write access to sensitive paths -3. **Shell restrictions** — Block dangerous shell commands -4. **Rate limits** — Cap tool invocations per agent per interval -5. **PII filters** — Redact sensitive data before model calls - -Configure policies in `squad.config.ts` under the `hooks` key: - -```typescript -export default defineConfig({ - hooks: { - fileGuards: [{ pattern: /\.env/, action: 'block' }], - shellRestrictions: { allowList: ['git', 'npm', 'node'] }, - rateLimits: { maxCallsPerMinute: 30 }, - }, -}); -``` diff --git a/docs/src/components/Footer.astro b/docs/src/components/Footer.astro new file mode 100644 index 000000000..3feb5b832 --- /dev/null +++ b/docs/src/components/Footer.astro @@ -0,0 +1,53 @@ +--- +const base = import.meta.env.BASE_URL; +--- + + diff --git a/docs/src/components/Header.astro b/docs/src/components/Header.astro new file mode 100644 index 000000000..306d4d57a --- /dev/null +++ b/docs/src/components/Header.astro @@ -0,0 +1,48 @@ +--- +import ThemeToggle from './ThemeToggle.astro'; +const base = import.meta.env.BASE_URL; +--- + +
+
+ + + + + + Squad + Squad + + + + + + +
+ + + + + + +
+
+
diff --git a/docs/src/components/Sidebar.astro b/docs/src/components/Sidebar.astro new file mode 100644 index 000000000..5fec4dcfe --- /dev/null +++ b/docs/src/components/Sidebar.astro @@ -0,0 +1,87 @@ +--- +import { NAV_SECTIONS, STANDALONE_PAGES } from '../navigation'; + +interface Props { + currentSlug?: string; +} + +const { currentSlug = '' } = Astro.props; +const base = import.meta.env.BASE_URL; +--- + + + + + + + diff --git a/docs/src/components/ThemeToggle.astro b/docs/src/components/ThemeToggle.astro new file mode 100644 index 000000000..68bbff5b3 --- /dev/null +++ b/docs/src/components/ThemeToggle.astro @@ -0,0 +1,25 @@ +--- +const base = import.meta.env.BASE_URL; +--- + + + + diff --git a/docs/blog/001-wave-0-the-team-that-built-itself.md b/docs/src/content/blog/001-wave-0-the-team-that-built-itself.md similarity index 100% rename from docs/blog/001-wave-0-the-team-that-built-itself.md rename to docs/src/content/blog/001-wave-0-the-team-that-built-itself.md diff --git a/docs/blog/001a-the-squad-squad-problem.md b/docs/src/content/blog/001a-the-squad-squad-problem.md similarity index 100% rename from docs/blog/001a-the-squad-squad-problem.md rename to docs/src/content/blog/001a-the-squad-squad-problem.md diff --git a/docs/blog/001b-meet-the-squad.md b/docs/src/content/blog/001b-meet-the-squad.md similarity index 100% rename from docs/blog/001b-meet-the-squad.md rename to docs/src/content/blog/001b-meet-the-squad.md diff --git a/docs/blog/001c-first-pr-amolchanov.md b/docs/src/content/blog/001c-first-pr-amolchanov.md similarity index 100% rename from docs/blog/001c-first-pr-amolchanov.md rename to docs/src/content/blog/001c-first-pr-amolchanov.md diff --git a/docs/blog/002-first-community-pr.md b/docs/src/content/blog/002-first-community-pr.md similarity index 100% rename from docs/blog/002-first-community-pr.md rename to docs/src/content/blog/002-first-community-pr.md diff --git a/docs/blog/003-super-bowl-weekend.md b/docs/src/content/blog/003-super-bowl-weekend.md similarity index 100% rename from docs/blog/003-super-bowl-weekend.md rename to docs/src/content/blog/003-super-bowl-weekend.md diff --git a/docs/blog/004-v020-release.md b/docs/src/content/blog/004-v020-release.md similarity index 100% rename from docs/blog/004-v020-release.md rename to docs/src/content/blog/004-v020-release.md diff --git a/docs/blog/005-v030-give-it-a-brain.md b/docs/src/content/blog/005-v030-give-it-a-brain.md similarity index 100% rename from docs/blog/005-v030-give-it-a-brain.md rename to docs/src/content/blog/005-v030-give-it-a-brain.md diff --git a/docs/blog/006-first-external-deployment.md b/docs/src/content/blog/006-first-external-deployment.md similarity index 100% rename from docs/blog/006-first-external-deployment.md rename to docs/src/content/blog/006-first-external-deployment.md diff --git a/docs/blog/007-first-video-coverage.md b/docs/src/content/blog/007-first-video-coverage.md similarity index 100% rename from docs/blog/007-first-video-coverage.md rename to docs/src/content/blog/007-first-video-coverage.md diff --git a/docs/blog/008-v040-release.md b/docs/src/content/blog/008-v040-release.md similarity index 100% rename from docs/blog/008-v040-release.md rename to docs/src/content/blog/008-v040-release.md diff --git a/docs/blog/009-v040-sprint-progress.md b/docs/src/content/blog/009-v040-sprint-progress.md similarity index 100% rename from docs/blog/009-v040-sprint-progress.md rename to docs/src/content/blog/009-v040-sprint-progress.md diff --git a/docs/blog/010-v041-patch-release.md b/docs/src/content/blog/010-v041-patch-release.md similarity index 100% rename from docs/blog/010-v041-patch-release.md rename to docs/src/content/blog/010-v041-patch-release.md diff --git a/docs/blog/011-skills-system-learning-from-work.md b/docs/src/content/blog/011-skills-system-learning-from-work.md similarity index 100% rename from docs/blog/011-skills-system-learning-from-work.md rename to docs/src/content/blog/011-skills-system-learning-from-work.md diff --git a/docs/blog/012-trending-on-github.md b/docs/src/content/blog/012-trending-on-github.md similarity index 100% rename from docs/blog/012-trending-on-github.md rename to docs/src/content/blog/012-trending-on-github.md diff --git a/docs/blog/013-the-replatform-begins.md b/docs/src/content/blog/013-the-replatform-begins.md similarity index 100% rename from docs/blog/013-the-replatform-begins.md rename to docs/src/content/blog/013-the-replatform-begins.md diff --git a/docs/blog/014-wave-1-otel-and-aspire.md b/docs/src/content/blog/014-wave-1-otel-and-aspire.md similarity index 100% rename from docs/blog/014-wave-1-otel-and-aspire.md rename to docs/src/content/blog/014-wave-1-otel-and-aspire.md diff --git a/docs/blog/015-wave-2-the-repl-moment.md b/docs/src/content/blog/015-wave-2-the-repl-moment.md similarity index 100% rename from docs/blog/015-wave-2-the-repl-moment.md rename to docs/src/content/blog/015-wave-2-the-repl-moment.md diff --git a/docs/blog/016-wave-3-docs-that-teach.md b/docs/src/content/blog/016-wave-3-docs-that-teach.md similarity index 100% rename from docs/blog/016-wave-3-docs-that-teach.md rename to docs/src/content/blog/016-wave-3-docs-that-teach.md diff --git a/docs/blog/017-version-alignment.md b/docs/src/content/blog/017-version-alignment.md similarity index 100% rename from docs/blog/017-version-alignment.md rename to docs/src/content/blog/017-version-alignment.md diff --git a/docs/blog/018-the-adapter-chronicles.md b/docs/src/content/blog/018-the-adapter-chronicles.md similarity index 100% rename from docs/blog/018-the-adapter-chronicles.md rename to docs/src/content/blog/018-the-adapter-chronicles.md diff --git a/docs/blog/019-shaynes-remote-mode.md b/docs/src/content/blog/019-shaynes-remote-mode.md similarity index 100% rename from docs/blog/019-shaynes-remote-mode.md rename to docs/src/content/blog/019-shaynes-remote-mode.md diff --git a/docs/blog/020-docs-reborn.md b/docs/src/content/blog/020-docs-reborn.md similarity index 100% rename from docs/blog/020-docs-reborn.md rename to docs/src/content/blog/020-docs-reborn.md diff --git a/docs/blog/021-the-migration.md b/docs/src/content/blog/021-the-migration.md similarity index 100% rename from docs/blog/021-the-migration.md rename to docs/src/content/blog/021-the-migration.md diff --git a/docs/blog/022-welcome-to-the-new-squad.md b/docs/src/content/blog/022-welcome-to-the-new-squad.md similarity index 100% rename from docs/blog/022-welcome-to-the-new-squad.md rename to docs/src/content/blog/022-welcome-to-the-new-squad.md diff --git a/docs/blog/023-subsquads-horizontal-scaling.md b/docs/src/content/blog/023-subsquads-horizontal-scaling.md similarity index 97% rename from docs/blog/023-subsquads-horizontal-scaling.md rename to docs/src/content/blog/023-subsquads-horizontal-scaling.md index 6eb0dbed8..5f647603b 100644 --- a/docs/blog/023-subsquads-horizontal-scaling.md +++ b/docs/src/content/blog/023-subsquads-horizontal-scaling.md @@ -1,133 +1,133 @@ ---- -title: "SubSquads — Scaling Squad Across Multiple Codespaces" -date: 2026-03-05 -author: "Tamir Dresher (Community Contributor)" -wave: null -tags: [squad, subsquads, scaling, codespaces, horizontal-scaling, multi-instance, community] -status: draft -hero: "Squad SubSquads lets you partition a repo's work across multiple Codespaces — each running its own scoped Squad instance. One repo, multiple AI teams, zero conflicts." ---- - -# SubSquads — Scaling Squad Across Multiple Codespaces - -> Blog post #23 — A community contribution: horizontal scaling for Squad. - -## The Problem We Hit - -We were building a multiplayer Tetris game with Squad. One team, 30 issues — UI, backend, cloud infra. Squad handled it fine at first, but as the issue count grew, a single Squad instance became a bottleneck. Agents stepped on each other in shared packages, there was no workflow enforcement, and we had no way to scope each Codespace to its slice of work. - -So we built SubSquads. - -## What Are SubSquads? - -SubSquads partition your repo's issues into labeled subsets. Each Codespace (or machine) runs one SubSquad, scoped to matching issues only. - -``` -┌─────────────────────────────────────────────────┐ -│ Repository: acme/starship │ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ -│ │ Codespace 1 │ │ Codespace 2 │ │ Codespace 3│ │ -│ │ team:bridge │ │ team:engine │ │ team:ops │ │ -│ │ UI + API │ │ Core engine │ │ Infra + CI │ │ -│ └─────────────┘ └─────────────┘ └───────────┘ │ -│ │ -│ Ralph only picks up issues matching │ -│ the active SubSquad's label. │ -└─────────────────────────────────────────────────┘ -``` - -## How It Works - -**1. Define SubSquads** in `.squad/streams.json`: - -```json -{ - "defaultWorkflow": "branch-per-issue", - "workstreams": [ - { - "name": "bridge", - "labelFilter": "team:bridge", - "folderScope": ["src/api", "src/ui"], - "description": "Bridge crew — API and UI" - }, - { - "name": "engine", - "labelFilter": "team:engine", - "folderScope": ["src/core"], - "description": "Engineering — core systems" - } - ] -} -``` - -**2. Activate a SubSquad:** - -```bash -# Via environment variable (ideal for Codespaces) -export SQUAD_TEAM=bridge - -# Or via CLI (local machines) -squad subsquads activate bridge -``` - -**3. Run Squad normally.** Ralph will only pick up issues labeled `team:bridge`. Agents enforce branch+PR workflow. `folderScope` guides where agents focus (advisory, not enforced — shared code is still accessible). - -## The Tetris Experiment - -We validated this with [tamirdresher/squad-tetris](https://github.com/tamirdresher/squad-tetris) — 3 Codespaces, 30 issues, Star Trek TNG crew names: - -| Codespace | SubSquad | Squad Members | Focus | -|-----------|-----------|---------------|-------| -| CS-1 | `ui` | Riker, Troi | React game board, animations | -| CS-2 | `backend` | Geordi, Worf | WebSocket server, game state | -| CS-3 | `cloud` | Picard, Crusher | Azure, CI/CD, deployment | - -**Results:** 9 issues closed, 16 branches created, 6+ PRs merged, real code shipped across all three teams. We discovered that `folderScope` needs to be advisory (shared packages require cross-team access) and that workflow enforcement (`branch-per-issue`) is critical to prevent direct commits to main. - -## CLI Commands - -```bash -squad subsquads list # Show all configured SubSquads -squad subsquads status # Activity per SubSquad (branches, PRs) -squad subsquads activate X # Activate a SubSquad for this machine -``` - -## Resolution Chain - -Squad resolves the active SubSquad in priority order: - -1. `SQUAD_TEAM` environment variable -2. `.squad-workstream` file (written by `activate`, gitignored) -3. Auto-select if exactly one SubSquad is defined -4. No SubSquad → single-squad mode (backward compatible) - -## Key Design Decisions - -- **folderScope is advisory** — agents prefer these directories but can modify shared code when needed -- **Workflow enforcement** — `branch-per-issue` means every issue gets a branch and PR, never direct commits to main -- **Backward compatible** — repos without `streams.json` work exactly as before -- **Single-machine testing** — use `squad subsquads activate` to switch SubSquads sequentially without needing multiple Codespaces - -## What's Next - -We're looking at cross-SubSquad coordination — a central dashboard showing all SubSquads' activity, conflict detection for shared files, and auto-merge coordination. See the [PRD](https://github.com/bradygaster/squad/issues/200) for the full roadmap. - -The community decided on the name "SubSquads" — each partition is a SubSquad of the main Squad. - -## Try It - -```bash -# Install Squad -npm install -g @bradygaster/squad-cli - -# Init in your repo -squad init - -# Create streams.json and label your issues -# Then activate and go -squad subsquads activate frontend -squad start -``` - -Full docs: [Scaling with SubSquads](../scenarios/scaling-workstreams.md) | [Multi-Codespace Setup](../scenarios/multi-codespace.md) | [SubSquads PRD](../specs/streams-prd.md) +--- +title: "SubSquads — Scaling Squad Across Multiple Codespaces" +date: 2026-03-05 +author: "Tamir Dresher (Community Contributor)" +wave: null +tags: [squad, subsquads, scaling, codespaces, horizontal-scaling, multi-instance, community] +status: draft +hero: "Squad SubSquads lets you partition a repo's work across multiple Codespaces — each running its own scoped Squad instance. One repo, multiple AI teams, zero conflicts." +--- + +# SubSquads — Scaling Squad Across Multiple Codespaces + +> Blog post #23 — A community contribution: horizontal scaling for Squad. + +## The Problem We Hit + +We were building a multiplayer Tetris game with Squad. One team, 30 issues — UI, backend, cloud infra. Squad handled it fine at first, but as the issue count grew, a single Squad instance became a bottleneck. Agents stepped on each other in shared packages, there was no workflow enforcement, and we had no way to scope each Codespace to its slice of work. + +So we built SubSquads. + +## What Are SubSquads? + +SubSquads partition your repo's issues into labeled subsets. Each Codespace (or machine) runs one SubSquad, scoped to matching issues only. + +``` +┌─────────────────────────────────────────────────┐ +│ Repository: acme/starship │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ +│ │ Codespace 1 │ │ Codespace 2 │ │ Codespace 3│ │ +│ │ team:bridge │ │ team:engine │ │ team:ops │ │ +│ │ UI + API │ │ Core engine │ │ Infra + CI │ │ +│ └─────────────┘ └─────────────┘ └───────────┘ │ +│ │ +│ Ralph only picks up issues matching │ +│ the active SubSquad's label. │ +└─────────────────────────────────────────────────┘ +``` + +## How It Works + +**1. Define SubSquads** in `.squad/streams.json`: + +```json +{ + "defaultWorkflow": "branch-per-issue", + "workstreams": [ + { + "name": "bridge", + "labelFilter": "team:bridge", + "folderScope": ["src/api", "src/ui"], + "description": "Bridge crew — API and UI" + }, + { + "name": "engine", + "labelFilter": "team:engine", + "folderScope": ["src/core"], + "description": "Engineering — core systems" + } + ] +} +``` + +**2. Activate a SubSquad:** + +```bash +# Via environment variable (ideal for Codespaces) +export SQUAD_TEAM=bridge + +# Or via CLI (local machines) +squad subsquads activate bridge +``` + +**3. Run Squad normally.** Ralph will only pick up issues labeled `team:bridge`. Agents enforce branch+PR workflow. `folderScope` guides where agents focus (advisory, not enforced — shared code is still accessible). + +## The Tetris Experiment + +We validated this with [tamirdresher/squad-tetris](https://github.com/tamirdresher/squad-tetris) — 3 Codespaces, 30 issues, Star Trek TNG crew names: + +| Codespace | SubSquad | Squad Members | Focus | +|-----------|-----------|---------------|-------| +| CS-1 | `ui` | Riker, Troi | React game board, animations | +| CS-2 | `backend` | Geordi, Worf | WebSocket server, game state | +| CS-3 | `cloud` | Picard, Crusher | Azure, CI/CD, deployment | + +**Results:** 9 issues closed, 16 branches created, 6+ PRs merged, real code shipped across all three teams. We discovered that `folderScope` needs to be advisory (shared packages require cross-team access) and that workflow enforcement (`branch-per-issue`) is critical to prevent direct commits to main. + +## CLI Commands + +```bash +squad subsquads list # Show all configured SubSquads +squad subsquads status # Activity per SubSquad (branches, PRs) +squad subsquads activate X # Activate a SubSquad for this machine +``` + +## Resolution Chain + +Squad resolves the active SubSquad in priority order: + +1. `SQUAD_TEAM` environment variable +2. `.squad-workstream` file (written by `activate`, gitignored) +3. Auto-select if exactly one SubSquad is defined +4. No SubSquad → single-squad mode (backward compatible) + +## Key Design Decisions + +- **folderScope is advisory** — agents prefer these directories but can modify shared code when needed +- **Workflow enforcement** — `branch-per-issue` means every issue gets a branch and PR, never direct commits to main +- **Backward compatible** — repos without `streams.json` work exactly as before +- **Single-machine testing** — use `squad subsquads activate` to switch SubSquads sequentially without needing multiple Codespaces + +## What's Next + +We're looking at cross-SubSquad coordination — a central dashboard showing all SubSquads' activity, conflict detection for shared files, and auto-merge coordination. See the [PRD](https://github.com/bradygaster/squad/issues/200) for the full roadmap. + +The community decided on the name "SubSquads" — each partition is a SubSquad of the main Squad. + +## Try It + +```bash +# Install Squad +npm install -g @bradygaster/squad-cli + +# Init in your repo +squad init + +# Create streams.json and label your issues +# Then activate and go +squad subsquads activate frontend +squad start +``` + +Full docs: [Scaling with SubSquads](../scenarios/scaling-workstreams.md) | [Multi-Codespace Setup](../scenarios/multi-codespace.md) | [SubSquads PRD](../specs/streams-prd.md) diff --git a/docs/blog/024-v0823-release.md b/docs/src/content/blog/024-v0823-release.md similarity index 100% rename from docs/blog/024-v0823-release.md rename to docs/src/content/blog/024-v0823-release.md diff --git a/docs/blog/025-squad-goes-enterprise-azure-devops.md b/docs/src/content/blog/025-squad-goes-enterprise-azure-devops.md similarity index 97% rename from docs/blog/025-squad-goes-enterprise-azure-devops.md rename to docs/src/content/blog/025-squad-goes-enterprise-azure-devops.md index c62d86d19..498188143 100644 --- a/docs/blog/025-squad-goes-enterprise-azure-devops.md +++ b/docs/src/content/blog/025-squad-goes-enterprise-azure-devops.md @@ -1,226 +1,226 @@ ---- -title: "Squad Goes Enterprise — Azure DevOps, Area Paths, and Cross-Project Work Items" -date: 2026-03-07 -author: "Tamir Dresher" -wave: null -tags: [squad, azure-devops, enterprise, platform-adapter, work-items, area-paths, iteration-paths] -status: published -hero: "Squad now speaks Azure DevOps natively — auto-detection, configurable work item types, area/iteration paths, and cross-project support for enterprise environments." ---- - -# Squad Goes Enterprise — Azure DevOps, Area Paths, and Cross-Project Work Items - -> Blog post #25 — How Squad learned to work with enterprise ADO environments where nothing is "standard." - -## The Problem - -GitHub repos have issues. Simple. One repo, one issue tracker, one set of labels. - -Enterprise Azure DevOps? Not so much. Your code might live in one project, your work items in another. Your org might use "Scenario" instead of "User Story." Your team's backlog is scoped by area paths. Your sprints use iteration paths. And there's no PAT to manage — you authenticate via `az login`. - -Squad needed to understand all of this. Not just "detect ADO" — actually *work* in enterprise ADO environments where every project has its own rules. - -## What Shipped - -### Platform Auto-Detection - -Squad reads your git remote URL and figures out where you are: - -``` -https://dev.azure.com/myorg/myproject/_git/myrepo → azure-devops -git@ssh.dev.azure.com:v3/myorg/myproject/myrepo → azure-devops -https://myorg.visualstudio.com/myproject/_git/myrepo → azure-devops -``` - -No configuration needed. `squad init` detects ADO and: -- Skips `.github/workflows/` generation (those don't run in ADO) -- Writes `"platform": "azure-devops"` to `.squad/config.json` -- Generates ADO-appropriate MCP config examples - -### Configurable Work Item Types - -Not every ADO project uses "User Story." Some use "Scenario," "Bug," or custom types locked down by org policy. Now you can configure it: - -```json -{ - "version": 1, - "platform": "azure-devops", - "ado": { - "defaultWorkItemType": "Scenario" - } -} -``` - -Squad uses your configured type for all work item creation — Ralph triage, agent task creation, everything. - -### Area Paths — Route to the Right Team - -In enterprise ADO, area paths determine which team's backlog a work item appears in. A work item in `"MyProject\Frontend"` shows up on the Frontend team's board. One in `"MyProject\Platform"` goes to Platform. - -```json -{ - "ado": { - "areaPath": "MyProject\\Team Alpha" - } -} -``` - -Now when Squad creates work items, they land on the right team's board — not lost in the root backlog. - -### Iteration Paths — Sprint Placement - -Same story for sprints. Enterprise teams plan in iterations, and work items need to appear in the right sprint: - -```json -{ - "ado": { - "iterationPath": "MyProject\\Sprint 5" - } -} -``` - -### Cross-Project Work Items — The Enterprise Killer Feature - -Here's the one that matters most for large organizations: **your git repo and your work items might live in completely different ADO projects — or even different orgs.** - -Common pattern in enterprise: -- **Code** lives in `Engineering/my-service` (locked-down project with strict CI) -- **Work items** live in `Planning/team-backlog` (PM-managed project with custom process templates) - -Squad now supports this cleanly: - -```json -{ - "version": 1, - "platform": "azure-devops", - "ado": { - "org": "planning-org", - "project": "team-backlog", - "defaultWorkItemType": "Scenario", - "areaPath": "team-backlog\\Alpha Squad", - "iterationPath": "team-backlog\\2026-Q1\\Sprint 5" - } -} -``` - -When `ado.org` or `ado.project` are set, Squad uses them for all work item operations (create, query, tag, comment) while continuing to use the git remote's org/project for repo operations (branches, PRs, commits). - -The WIQL queries, `az boards` commands, and Ralph's triage loop all respect this split. - -## The Full Config Reference - -All fields are optional. Omit any field to use the default. - -| Field | Default | Description | -|-------|---------|-------------| -| `ado.org` | *(from git remote)* | ADO org for work items | -| `ado.project` | *(from git remote)* | ADO project for work items | -| `ado.defaultWorkItemType` | `"User Story"` | Type for new work items | -| `ado.areaPath` | *(project default)* | Team backlog routing | -| `ado.iterationPath` | *(project default)* | Sprint board placement | - -## Security — No PATs Needed - -Squad uses `az login` for authentication. No Personal Access Tokens to rotate, no secrets in config files. Your Azure CLI session handles everything. - -For environments where MCP tools are available, Squad also supports the Azure DevOps MCP server for richer API access: - -```json -{ - "mcpServers": { - "azure-devops": { - "command": "npx", - "args": ["-y", "@azure/devops-mcp-server"] - } - } -} -``` - -## Security Hardening - -The ADO adapter went through a thorough security review: - -- **Shell injection prevention** — All `execSync` calls replaced with `execFileSync` (args as arrays, not concatenated strings) -- **WIQL injection prevention** — `escapeWiql()` helper doubles single-quotes in all user-supplied values -- **Bearer token protection** — Planner adapter passes tokens via `curl --config stdin` instead of CLI args (invisible to `ps aux`) - -## What We Tested - -External integration testing against real ADO environments (WDATP, OS, SquadDemo projects): - -| Test | Result | -|------|--------| -| ADO project connectivity | ✅ | -| Repo discovery | ✅ | -| Branch creation | ✅ | -| Git clone + push | ✅ | -| Squad init (platform detection) | ✅ | -| PR creation + auto-complete | ✅ | -| PR read/list/comment | ✅ | -| Commit search | ✅ | -| Work item CRUD | ✅ | -| WIQL tag queries | ✅ | -| Cross-project work items | ✅ | - -The only blockers encountered were project-specific restrictions (locked-down work item types in WDATP) — not Squad bugs. - -## Ralph in ADO - -Ralph's coordinator prompt is now platform-aware. When running against ADO, Ralph uses WIQL queries instead of GitHub issue queries: - -```wiql -SELECT [System.Id] FROM WorkItems -WHERE [System.Tags] Contains 'squad' - AND [System.State] <> 'Closed' - AND [System.TeamProject] = 'team-backlog' -ORDER BY [System.CreatedDate] DESC -``` - -The full triage → assign → branch → PR → merge loop works end-to-end with ADO. - -## Ralph + ADO: The Governance Fix - -The coordinator prompt (`squad.agent.md`) is what tells Ralph *where* to look for work. Previously, it only had GitHub commands — `gh issue list`, `gh pr list`. Even if the ADO adapter was perfect, Ralph would still scan GitHub because that's what the governance file told it to do. - -We fixed this at every level: -- **MCP detection** — Added `azure-devops-*` to the tool prefix table so the coordinator recognizes ADO MCP tools -- **Platform Detection section** — New section in the governance file explaining how to detect GitHub vs ADO from the git remote -- **Issue Awareness** — Now shows both GitHub and ADO queries, with instructions to read `.squad/config.json` first -- **Ralph Step 1** — Platform-aware scan with both GitHub and ADO command blocks, plus the critical instruction: *"Read `.squad/config.json` for the `ado` section FIRST — do NOT guess the ADO project from the repo name"* - -This is the kind of bug that's invisible in unit tests — the code works, but the governance prompt doesn't tell the coordinator to use it. - -## Getting Started - -```bash -# 1. Install Squad -npm install -g @bradygaster/squad-cli - -# 2. Clone your ADO repo -git clone https://dev.azure.com/your-org/your-project/_git/your-repo -cd your-repo - -# 3. Make sure az CLI is set up -az login -az extension add --name azure-devops - -# 4. Init Squad (auto-detects ADO) -squad init - -# 5. Edit .squad/config.json if you need custom work item config -# 6. Start working! -``` - -Full documentation: [Enterprise Platforms Guide](../features/enterprise-platforms.md) - -## What's Next - -- **Process template introspection** — Auto-detect available work item types from the ADO process template (#240) -- **ADO webhook integration** — Real-time work item change notifications -- **Azure Pipelines scaffolding** — Generate pipeline YAML during `squad init` for ADO repos - ---- - -*The enterprise doesn't bend to your tools. Your tools bend to the enterprise. Squad now does.* - -PR: [#191 — Azure DevOps platform adapter](https://github.com/bradygaster/squad/pull/191) +--- +title: "Squad Goes Enterprise — Azure DevOps, Area Paths, and Cross-Project Work Items" +date: 2026-03-07 +author: "Tamir Dresher" +wave: null +tags: [squad, azure-devops, enterprise, platform-adapter, work-items, area-paths, iteration-paths] +status: published +hero: "Squad now speaks Azure DevOps natively — auto-detection, configurable work item types, area/iteration paths, and cross-project support for enterprise environments." +--- + +# Squad Goes Enterprise — Azure DevOps, Area Paths, and Cross-Project Work Items + +> Blog post #25 — How Squad learned to work with enterprise ADO environments where nothing is "standard." + +## The Problem + +GitHub repos have issues. Simple. One repo, one issue tracker, one set of labels. + +Enterprise Azure DevOps? Not so much. Your code might live in one project, your work items in another. Your org might use "Scenario" instead of "User Story." Your team's backlog is scoped by area paths. Your sprints use iteration paths. And there's no PAT to manage — you authenticate via `az login`. + +Squad needed to understand all of this. Not just "detect ADO" — actually *work* in enterprise ADO environments where every project has its own rules. + +## What Shipped + +### Platform Auto-Detection + +Squad reads your git remote URL and figures out where you are: + +``` +https://dev.azure.com/myorg/myproject/_git/myrepo → azure-devops +git@ssh.dev.azure.com:v3/myorg/myproject/myrepo → azure-devops +https://myorg.visualstudio.com/myproject/_git/myrepo → azure-devops +``` + +No configuration needed. `squad init` detects ADO and: +- Skips `.github/workflows/` generation (those don't run in ADO) +- Writes `"platform": "azure-devops"` to `.squad/config.json` +- Generates ADO-appropriate MCP config examples + +### Configurable Work Item Types + +Not every ADO project uses "User Story." Some use "Scenario," "Bug," or custom types locked down by org policy. Now you can configure it: + +```json +{ + "version": 1, + "platform": "azure-devops", + "ado": { + "defaultWorkItemType": "Scenario" + } +} +``` + +Squad uses your configured type for all work item creation — Ralph triage, agent task creation, everything. + +### Area Paths — Route to the Right Team + +In enterprise ADO, area paths determine which team's backlog a work item appears in. A work item in `"MyProject\Frontend"` shows up on the Frontend team's board. One in `"MyProject\Platform"` goes to Platform. + +```json +{ + "ado": { + "areaPath": "MyProject\\Team Alpha" + } +} +``` + +Now when Squad creates work items, they land on the right team's board — not lost in the root backlog. + +### Iteration Paths — Sprint Placement + +Same story for sprints. Enterprise teams plan in iterations, and work items need to appear in the right sprint: + +```json +{ + "ado": { + "iterationPath": "MyProject\\Sprint 5" + } +} +``` + +### Cross-Project Work Items — The Enterprise Killer Feature + +Here's the one that matters most for large organizations: **your git repo and your work items might live in completely different ADO projects — or even different orgs.** + +Common pattern in enterprise: +- **Code** lives in `Engineering/my-service` (locked-down project with strict CI) +- **Work items** live in `Planning/team-backlog` (PM-managed project with custom process templates) + +Squad now supports this cleanly: + +```json +{ + "version": 1, + "platform": "azure-devops", + "ado": { + "org": "planning-org", + "project": "team-backlog", + "defaultWorkItemType": "Scenario", + "areaPath": "team-backlog\\Alpha Squad", + "iterationPath": "team-backlog\\2026-Q1\\Sprint 5" + } +} +``` + +When `ado.org` or `ado.project` are set, Squad uses them for all work item operations (create, query, tag, comment) while continuing to use the git remote's org/project for repo operations (branches, PRs, commits). + +The WIQL queries, `az boards` commands, and Ralph's triage loop all respect this split. + +## The Full Config Reference + +All fields are optional. Omit any field to use the default. + +| Field | Default | Description | +|-------|---------|-------------| +| `ado.org` | *(from git remote)* | ADO org for work items | +| `ado.project` | *(from git remote)* | ADO project for work items | +| `ado.defaultWorkItemType` | `"User Story"` | Type for new work items | +| `ado.areaPath` | *(project default)* | Team backlog routing | +| `ado.iterationPath` | *(project default)* | Sprint board placement | + +## Security — No PATs Needed + +Squad uses `az login` for authentication. No Personal Access Tokens to rotate, no secrets in config files. Your Azure CLI session handles everything. + +For environments where MCP tools are available, Squad also supports the Azure DevOps MCP server for richer API access: + +```json +{ + "mcpServers": { + "azure-devops": { + "command": "npx", + "args": ["-y", "@azure/devops-mcp-server"] + } + } +} +``` + +## Security Hardening + +The ADO adapter went through a thorough security review: + +- **Shell injection prevention** — All `execSync` calls replaced with `execFileSync` (args as arrays, not concatenated strings) +- **WIQL injection prevention** — `escapeWiql()` helper doubles single-quotes in all user-supplied values +- **Bearer token protection** — Planner adapter passes tokens via `curl --config stdin` instead of CLI args (invisible to `ps aux`) + +## What We Tested + +External integration testing against real ADO environments (WDATP, OS, SquadDemo projects): + +| Test | Result | +|------|--------| +| ADO project connectivity | ✅ | +| Repo discovery | ✅ | +| Branch creation | ✅ | +| Git clone + push | ✅ | +| Squad init (platform detection) | ✅ | +| PR creation + auto-complete | ✅ | +| PR read/list/comment | ✅ | +| Commit search | ✅ | +| Work item CRUD | ✅ | +| WIQL tag queries | ✅ | +| Cross-project work items | ✅ | + +The only blockers encountered were project-specific restrictions (locked-down work item types in WDATP) — not Squad bugs. + +## Ralph in ADO + +Ralph's coordinator prompt is now platform-aware. When running against ADO, Ralph uses WIQL queries instead of GitHub issue queries: + +```wiql +SELECT [System.Id] FROM WorkItems +WHERE [System.Tags] Contains 'squad' + AND [System.State] <> 'Closed' + AND [System.TeamProject] = 'team-backlog' +ORDER BY [System.CreatedDate] DESC +``` + +The full triage → assign → branch → PR → merge loop works end-to-end with ADO. + +## Ralph + ADO: The Governance Fix + +The coordinator prompt (`squad.agent.md`) is what tells Ralph *where* to look for work. Previously, it only had GitHub commands — `gh issue list`, `gh pr list`. Even if the ADO adapter was perfect, Ralph would still scan GitHub because that's what the governance file told it to do. + +We fixed this at every level: +- **MCP detection** — Added `azure-devops-*` to the tool prefix table so the coordinator recognizes ADO MCP tools +- **Platform Detection section** — New section in the governance file explaining how to detect GitHub vs ADO from the git remote +- **Issue Awareness** — Now shows both GitHub and ADO queries, with instructions to read `.squad/config.json` first +- **Ralph Step 1** — Platform-aware scan with both GitHub and ADO command blocks, plus the critical instruction: *"Read `.squad/config.json` for the `ado` section FIRST — do NOT guess the ADO project from the repo name"* + +This is the kind of bug that's invisible in unit tests — the code works, but the governance prompt doesn't tell the coordinator to use it. + +## Getting Started + +```bash +# 1. Install Squad +npm install -g @bradygaster/squad-cli + +# 2. Clone your ADO repo +git clone https://dev.azure.com/your-org/your-project/_git/your-repo +cd your-repo + +# 3. Make sure az CLI is set up +az login +az extension add --name azure-devops + +# 4. Init Squad (auto-detects ADO) +squad init + +# 5. Edit .squad/config.json if you need custom work item config +# 6. Start working! +``` + +Full documentation: [Enterprise Platforms Guide](../features/enterprise-platforms.md) + +## What's Next + +- **Process template introspection** — Auto-detect available work item types from the ADO process template (#240) +- **ADO webhook integration** — Real-time work item change notifications +- **Azure Pipelines scaffolding** — Generate pipeline YAML during `squad init` for ADO repos + +--- + +*The enterprise doesn't bend to your tools. Your tools bend to the enterprise. Squad now does.* + +PR: [#191 — Azure DevOps platform adapter](https://github.com/bradygaster/squad/pull/191) diff --git a/docs/blog/026-whats-new-ado-comms-subsquads.md b/docs/src/content/blog/026-whats-new-ado-comms-subsquads.md similarity index 97% rename from docs/blog/026-whats-new-ado-comms-subsquads.md rename to docs/src/content/blog/026-whats-new-ado-comms-subsquads.md index d55b109fa..30cf45d3d 100644 --- a/docs/blog/026-whats-new-ado-comms-subsquads.md +++ b/docs/src/content/blog/026-whats-new-ado-comms-subsquads.md @@ -1,151 +1,151 @@ ---- -title: "What's New: Azure DevOps Adapter, CommunicationAdapter, SubSquads, and Security Hardening" -date: 2026-03-08 -author: "Tamir Dresher" -wave: 7 -tags: [squad, azure-devops, enterprise, platform-adapter, communication, subsquads, security] -status: published -hero: "Squad goes enterprise with native Azure DevOps support, adds a CommunicationAdapter for platform-agnostic agent-human messaging, renames Workstreams to SubSquads, and ships critical security hardening across all platform adapters." ---- - -# What's New: Azure DevOps Adapter, CommunicationAdapter, SubSquads, and Security Hardening - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - -> _This batch adds first-class Azure DevOps support, a pluggable communication layer, the community-voted SubSquads rename, and security fixes that prevent shell injection, WIQL injection, and bearer token exposure. 5 PRs merged, 153 new tests, 4 issues closed._ - ---- - -## What Shipped - -### 1. Azure DevOps Platform Adapter — The Enterprise Feature - -Squad now works natively with Azure DevOps. When your git remote points to `dev.azure.com` or `*.visualstudio.com`, Squad auto-detects the platform and adapts everything. - -**PlatformAdapter interface** — unified API for GitHub, ADO, and Planner: - -```typescript -interface PlatformAdapter { - listWorkItems(options): Promise; - createWorkItem(options): Promise; - createPullRequest(options): Promise; - mergePullRequest(id): Promise; - createBranch(name, fromBranch?): Promise; - // ... addTag, removeTag, addComment -} -``` - -Three adapters ship with the same interface: -- **AzureDevOpsAdapter** — `az boards` CLI for work items, `az repos` for PRs -- **GitHubAdapter** — `gh` CLI wrapper -- **PlannerAdapter** — Microsoft Graph API for hybrid work-item tracking - -**Configurable work items** via `.squad/config.json`: - -```json -{ - "platform": "azure-devops", - "ado": { - "org": "my-org", - "project": "planning-project", - "defaultWorkItemType": "Scenario", - "areaPath": "MyProject\\Team Alpha", - "iterationPath": "MyProject\\Sprint 5" - } -} -``` - -All fields are optional. Cross-project support means your work items can live in a completely different ADO org/project than your git repo. - -**Ralph on ADO** — the governance file (`squad.agent.md`) now includes a Platform Detection section, ADO WIQL commands for Ralph's scan cycle, and instructions to read `.squad/config.json` before any ADO command. - -**Docs:** [Enterprise Platforms Guide](../features/enterprise-platforms.md) | [Blog #025](025-squad-goes-enterprise-azure-devops.md) - -### 2. CommunicationAdapter — Agent-Human Messaging - -A new pluggable interface for agent-human communication. Scribe can post session summaries, Ralph can post board status, agents can escalate when blocked — all through a platform-appropriate channel. - -```typescript -interface CommunicationAdapter { - postUpdate(options): Promise<{ id: string; url?: string }>; - pollForReplies(options): Promise; - getNotificationUrl(threadId): string | undefined; -} -``` - -Four adapters: - -| Adapter | Phone-capable | Setup | -|---------|:---:|---| -| **FileLog** | Via git | Zero-config fallback | -| **GitHub Discussions** | ✅ Browser | Auto-detected | -| **ADO Work Item Discussions** | ✅ ADO mobile | Auto-detected | -| **Teams Webhook** | ✅ Teams mobile | Stubbed (Phase 2) | - -Factory auto-detects platform: `createCommunicationAdapter(repoRoot)`. - -### 3. SubSquads — The Community-Voted Rename - -Workstreams → SubSquads. The community decided. - -- CLI: `squad subsquads` (with `workstreams` and `streams` as deprecated aliases) -- Types: `SubSquadDefinition`, `SubSquadConfig`, `ResolvedSubSquad` -- Old names kept as `@deprecated` re-exports for backward compatibility -- Config file stays at `.squad/streams.json` (file rename deferred) - -### 4. Security Hardening - -Every platform adapter went through a community-driven 5-model security review (thanks [@wiisaacs](https://github.com/wiisaacs)): - -| Fix | What it prevents | -|-----|-----------------| -| `execSync` → `execFileSync` | Shell injection via user input | -| `escapeWiql()` helper | WIQL injection (SQL-style) in ADO queries | -| `curl --config stdin` | Bearer token invisible to `ps aux` | -| Case-insensitive detection | Mixed-case ADO URLs now detected correctly | -| Cross-platform draft filter | `findstr` → JMESPath (macOS/Linux compat) | -| PR status mapping | `active`→`open` for `gh` CLI compatibility | -| `gh issue create` fix | No `--json` flag — parse URL from stdout | - -### 5. ESM Runtime Patch + Secret Guardrails (Brady) - -- Runtime `Module._resolveFilename` intercept for Node 24+ ESM compatibility -- 5-layer secret defense architecture -- `.squad/skills/secret-handling/SKILL.md` team reference -- 59 TDD security hook tests -- Charter hardening for Trejo (Git & Release) and Drucker (CI/CD) - ---- - -## Quick Stats - -- ✅ 5 PRs merged (#191, #263, #268, #272, #266) -- ✅ 153 new tests (92 platform + 15 comms + 46 SubSquads) -- ✅ 59 security tests (Brady's sprint) -- ✅ 4 issues closed (#240, #261, #271, #273) -- ✅ Security review: 7 code fixes from 10 review comments -- ✅ External integration testing: 10/13 ADO tests passed - ---- - -## Breaking Changes - -None. All changes are additive. Repos without ADO remotes work exactly as before. Old `workstreams`/`streams` names still work as deprecated aliases. - ---- - -## Contributors - -- **[@tamirdresher](https://github.com/tamirdresher)** — ADO adapter, CommunicationAdapter, SubSquads rename, security fixes, docs, blog -- **[@wiisaacs](https://github.com/wiisaacs)** — 5-model security review with test validation -- **[@dfberry](https://github.com/dfberry)** — CommunicationAdapter requirements, tiered deployment proposal -- **[@bradygaster](https://github.com/bradygaster)** — ESM fix, secret guardrails sprint, SubSquads merge, architecture guidance - ---- - -## What's Next - -- **Process template introspection** — auto-detect ADO work item types (#240) -- **Teams webhook adapter** — full CommunicationAdapter implementation (#261) -- **Pre-existing test stabilization** — fix 14 flaky/environment-dependent tests (#273) -- **Persistent Ralph** — `squad watch` heartbeat improvements (#236) +--- +title: "What's New: Azure DevOps Adapter, CommunicationAdapter, SubSquads, and Security Hardening" +date: 2026-03-08 +author: "Tamir Dresher" +wave: 7 +tags: [squad, azure-devops, enterprise, platform-adapter, communication, subsquads, security] +status: published +hero: "Squad goes enterprise with native Azure DevOps support, adds a CommunicationAdapter for platform-agnostic agent-human messaging, renames Workstreams to SubSquads, and ships critical security hardening across all platform adapters." +--- + +# What's New: Azure DevOps Adapter, CommunicationAdapter, SubSquads, and Security Hardening + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +> _This batch adds first-class Azure DevOps support, a pluggable communication layer, the community-voted SubSquads rename, and security fixes that prevent shell injection, WIQL injection, and bearer token exposure. 5 PRs merged, 153 new tests, 4 issues closed._ + +--- + +## What Shipped + +### 1. Azure DevOps Platform Adapter — The Enterprise Feature + +Squad now works natively with Azure DevOps. When your git remote points to `dev.azure.com` or `*.visualstudio.com`, Squad auto-detects the platform and adapts everything. + +**PlatformAdapter interface** — unified API for GitHub, ADO, and Planner: + +```typescript +interface PlatformAdapter { + listWorkItems(options): Promise; + createWorkItem(options): Promise; + createPullRequest(options): Promise; + mergePullRequest(id): Promise; + createBranch(name, fromBranch?): Promise; + // ... addTag, removeTag, addComment +} +``` + +Three adapters ship with the same interface: +- **AzureDevOpsAdapter** — `az boards` CLI for work items, `az repos` for PRs +- **GitHubAdapter** — `gh` CLI wrapper +- **PlannerAdapter** — Microsoft Graph API for hybrid work-item tracking + +**Configurable work items** via `.squad/config.json`: + +```json +{ + "platform": "azure-devops", + "ado": { + "org": "my-org", + "project": "planning-project", + "defaultWorkItemType": "Scenario", + "areaPath": "MyProject\\Team Alpha", + "iterationPath": "MyProject\\Sprint 5" + } +} +``` + +All fields are optional. Cross-project support means your work items can live in a completely different ADO org/project than your git repo. + +**Ralph on ADO** — the governance file (`squad.agent.md`) now includes a Platform Detection section, ADO WIQL commands for Ralph's scan cycle, and instructions to read `.squad/config.json` before any ADO command. + +**Docs:** [Enterprise Platforms Guide](../features/enterprise-platforms.md) | [Blog #025](025-squad-goes-enterprise-azure-devops.md) + +### 2. CommunicationAdapter — Agent-Human Messaging + +A new pluggable interface for agent-human communication. Scribe can post session summaries, Ralph can post board status, agents can escalate when blocked — all through a platform-appropriate channel. + +```typescript +interface CommunicationAdapter { + postUpdate(options): Promise<{ id: string; url?: string }>; + pollForReplies(options): Promise; + getNotificationUrl(threadId): string | undefined; +} +``` + +Four adapters: + +| Adapter | Phone-capable | Setup | +|---------|:---:|---| +| **FileLog** | Via git | Zero-config fallback | +| **GitHub Discussions** | ✅ Browser | Auto-detected | +| **ADO Work Item Discussions** | ✅ ADO mobile | Auto-detected | +| **Teams Webhook** | ✅ Teams mobile | Stubbed (Phase 2) | + +Factory auto-detects platform: `createCommunicationAdapter(repoRoot)`. + +### 3. SubSquads — The Community-Voted Rename + +Workstreams → SubSquads. The community decided. + +- CLI: `squad subsquads` (with `workstreams` and `streams` as deprecated aliases) +- Types: `SubSquadDefinition`, `SubSquadConfig`, `ResolvedSubSquad` +- Old names kept as `@deprecated` re-exports for backward compatibility +- Config file stays at `.squad/streams.json` (file rename deferred) + +### 4. Security Hardening + +Every platform adapter went through a community-driven 5-model security review (thanks [@wiisaacs](https://github.com/wiisaacs)): + +| Fix | What it prevents | +|-----|-----------------| +| `execSync` → `execFileSync` | Shell injection via user input | +| `escapeWiql()` helper | WIQL injection (SQL-style) in ADO queries | +| `curl --config stdin` | Bearer token invisible to `ps aux` | +| Case-insensitive detection | Mixed-case ADO URLs now detected correctly | +| Cross-platform draft filter | `findstr` → JMESPath (macOS/Linux compat) | +| PR status mapping | `active`→`open` for `gh` CLI compatibility | +| `gh issue create` fix | No `--json` flag — parse URL from stdout | + +### 5. ESM Runtime Patch + Secret Guardrails (Brady) + +- Runtime `Module._resolveFilename` intercept for Node 24+ ESM compatibility +- 5-layer secret defense architecture +- `.squad/skills/secret-handling/SKILL.md` team reference +- 59 TDD security hook tests +- Charter hardening for Trejo (Git & Release) and Drucker (CI/CD) + +--- + +## Quick Stats + +- ✅ 5 PRs merged (#191, #263, #268, #272, #266) +- ✅ 153 new tests (92 platform + 15 comms + 46 SubSquads) +- ✅ 59 security tests (Brady's sprint) +- ✅ 4 issues closed (#240, #261, #271, #273) +- ✅ Security review: 7 code fixes from 10 review comments +- ✅ External integration testing: 10/13 ADO tests passed + +--- + +## Breaking Changes + +None. All changes are additive. Repos without ADO remotes work exactly as before. Old `workstreams`/`streams` names still work as deprecated aliases. + +--- + +## Contributors + +- **[@tamirdresher](https://github.com/tamirdresher)** — ADO adapter, CommunicationAdapter, SubSquads rename, security fixes, docs, blog +- **[@wiisaacs](https://github.com/wiisaacs)** — 5-model security review with test validation +- **[@dfberry](https://github.com/dfberry)** — CommunicationAdapter requirements, tiered deployment proposal +- **[@bradygaster](https://github.com/bradygaster)** — ESM fix, secret guardrails sprint, SubSquads merge, architecture guidance + +--- + +## What's Next + +- **Process template introspection** — auto-detect ADO work item types (#240) +- **Teams webhook adapter** — full CommunicationAdapter implementation (#261) +- **Pre-existing test stabilization** — fix 14 flaky/environment-dependent tests (#273) +- **Persistent Ralph** — `squad watch` heartbeat improvements (#236) diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts new file mode 100644 index 000000000..eb6b9816a --- /dev/null +++ b/docs/src/content/config.ts @@ -0,0 +1,22 @@ +import { defineCollection, z } from 'astro:content'; +import { glob } from 'astro/loaders'; + +const docs = defineCollection({ + loader: glob({ pattern: '**/*.md', base: './src/content/docs' }), + schema: z.object({ + title: z.string().optional(), + description: z.string().optional(), + order: z.number().optional(), + }), +}); + +const blog = defineCollection({ + loader: glob({ pattern: '**/*.md', base: './src/content/blog' }), + schema: z.object({ + title: z.string().optional(), + description: z.string().optional(), + date: z.coerce.string().optional(), + }), +}); + +export const collections = { docs, blog }; diff --git a/docs/community.md b/docs/src/content/docs/community.md similarity index 100% rename from docs/community.md rename to docs/src/content/docs/community.md diff --git a/docs/concepts/github-workflow.md b/docs/src/content/docs/concepts/github-workflow.md similarity index 100% rename from docs/concepts/github-workflow.md rename to docs/src/content/docs/concepts/github-workflow.md diff --git a/docs/concepts/memory-and-knowledge.md b/docs/src/content/docs/concepts/memory-and-knowledge.md similarity index 100% rename from docs/concepts/memory-and-knowledge.md rename to docs/src/content/docs/concepts/memory-and-knowledge.md diff --git a/docs/concepts/parallel-work.md b/docs/src/content/docs/concepts/parallel-work.md similarity index 100% rename from docs/concepts/parallel-work.md rename to docs/src/content/docs/concepts/parallel-work.md diff --git a/docs/concepts/portability.md b/docs/src/content/docs/concepts/portability.md similarity index 100% rename from docs/concepts/portability.md rename to docs/src/content/docs/concepts/portability.md diff --git a/docs/concepts/your-team.md b/docs/src/content/docs/concepts/your-team.md similarity index 100% rename from docs/concepts/your-team.md rename to docs/src/content/docs/concepts/your-team.md diff --git a/docs/cookbook/recipes.md b/docs/src/content/docs/cookbook/recipes.md similarity index 100% rename from docs/cookbook/recipes.md rename to docs/src/content/docs/cookbook/recipes.md diff --git a/docs/features/ceremonies.md b/docs/src/content/docs/features/ceremonies.md similarity index 100% rename from docs/features/ceremonies.md rename to docs/src/content/docs/features/ceremonies.md diff --git a/docs/features/consult-mode.md b/docs/src/content/docs/features/consult-mode.md similarity index 100% rename from docs/features/consult-mode.md rename to docs/src/content/docs/features/consult-mode.md diff --git a/docs/features/copilot-coding-agent.md b/docs/src/content/docs/features/copilot-coding-agent.md similarity index 100% rename from docs/features/copilot-coding-agent.md rename to docs/src/content/docs/features/copilot-coding-agent.md diff --git a/docs/features/directives.md b/docs/src/content/docs/features/directives.md similarity index 100% rename from docs/features/directives.md rename to docs/src/content/docs/features/directives.md diff --git a/docs/features/enterprise-platforms.md b/docs/src/content/docs/features/enterprise-platforms.md similarity index 97% rename from docs/features/enterprise-platforms.md rename to docs/src/content/docs/features/enterprise-platforms.md index 527a8ab29..ca51877ae 100644 --- a/docs/features/enterprise-platforms.md +++ b/docs/src/content/docs/features/enterprise-platforms.md @@ -1,185 +1,185 @@ -# Enterprise Platforms - -Squad supports Azure DevOps and Microsoft Planner in addition to GitHub. When your git remote points to Azure DevOps, Squad automatically detects the platform and adapts its commands. For work-item tracking, Squad also supports a hybrid model where code lives in one platform and tasks live in Microsoft Planner. - -## Prerequisites - -1. **Azure CLI** — Install from [https://aka.ms/install-az-cli](https://aka.ms/install-az-cli) -2. **Azure DevOps extension** — `az extension add --name azure-devops` -3. **Login** — `az login` -4. **Set defaults** — `az devops configure --defaults organization=https://dev.azure.com/YOUR_ORG project=YOUR_PROJECT` - -Verify setup: - -```bash -az devops configure --list -# Should show organization and project -``` - -## How It Works - -Squad auto-detects the platform from your git remote URL: - -| Remote URL pattern | Detected platform | -|---|---| -| `github.com` | GitHub | -| `dev.azure.com` | Azure DevOps | -| `*.visualstudio.com` | Azure DevOps | -| `ssh.dev.azure.com` | Azure DevOps | - -## Differences from GitHub - -### Work Items vs Issues - -| GitHub | Azure DevOps | -|---|---| -| Issues | Work Items | -| Labels (e.g., `squad:alice`) | Tags (e.g., `squad:alice`) | -| `gh issue list --label X` | WIQL query via `az boards query` | -| `gh issue edit --add-label` | `az boards work-item update --fields "System.Tags=..."` | - -### Pull Requests - -| GitHub | Azure DevOps | -|---|---| -| `gh pr list` | `az repos pr list` | -| `gh pr create` | `az repos pr create` | -| `gh pr merge` | `az repos pr update --status completed` | -| Review: Approved / Changes Requested | Vote: 10 (approved) / -10 (rejected) | - -### Branch Operations - -Branch operations use the same `git` commands on both platforms. Squad creates branches with the naming convention `squad/{id}-{slug}`. - -## Ralph on Azure DevOps - -Ralph works identically on ADO — he scans for untriaged work items using WIQL queries instead of GitHub label filters: - -``` -# GitHub -gh issue list --label "squad:untriaged" --json number,title,labels - -# Azure DevOps -az boards query --wiql "SELECT [System.Id],[System.Title],[System.Tags] FROM WorkItems WHERE [System.Tags] Contains 'squad:untriaged'" -``` - -Tag assignment uses the same `squad:{member}` convention, stored as ADO work item tags separated by `;`. - -## Configuration - -Squad auto-detects ADO from the git remote URL. For basic use, no extra configuration is needed. - -### Work Item Configuration - -When your ADO environment has custom work item types, area paths, iterations, or when work items live in a **different project or org** than the git repo, configure the `ado` section in `.squad/config.json`: - -```json -{ - "version": 1, - "teamRoot": "/path/to/repo", - "platform": "azure-devops", - "ado": { - "org": "my-org", - "project": "my-work-items-project", - "defaultWorkItemType": "Scenario", - "areaPath": "MyProject\\Team Alpha", - "iterationPath": "MyProject\\Sprint 5" - } -} -``` - -| Field | Default | Description | -|-------|---------|-------------| -| `ado.org` | *(from git remote)* | ADO org for work items — set when work items are in a different org than the repo | -| `ado.project` | *(from git remote)* | ADO project for work items — set when work items are in a different project | -| `ado.defaultWorkItemType` | `"User Story"` | Default type for new work items. Some orgs use `"Scenario"`, `"Bug"`, or custom types | -| `ado.areaPath` | *(project default)* | Area path for new work items — controls which team's backlog they appear in | -| `ado.iterationPath` | *(project default)* | Iteration/sprint path — controls which sprint board work items appear on | - -All fields are optional. Omitted fields use the defaults shown above. - -### Authentication - -Squad uses the Azure CLI for ADO authentication — **no Personal Access Tokens (PATs) needed.** Run `az login` once, and Squad agents use your authenticated session for all operations. - -Alternatively, if the Azure DevOps MCP server is configured in your environment, Squad will use it automatically for richer API access. Add it to `.copilot/mcp-config.json`: - -```json -{ - "mcpServers": { - "azure-devops": { - "command": "npx", - "args": ["-y", "@azure/devops-mcp-server"] - } - } -} -``` - -Squad prefers MCP tools when available, falling back to `az` CLI when not. - -To explicitly check which platform Squad detects: - -```typescript -import { detectPlatform } from '@bradygaster/squad/platform'; - -const platform = detectPlatform('/path/to/repo'); -// Returns 'github', 'azure-devops', or 'planner' -``` - ---- - -## Microsoft Planner Support (Hybrid Model) - -Squad supports a hybrid model where your **repository** lives in GitHub or Azure DevOps, but **work items** are tracked in Microsoft Planner. This is common in enterprise environments where project management uses Planner while engineering uses ADO or GitHub for code. - -### How It Works - -- Planner **buckets** map to squad assignments: `squad:untriaged`, `squad:riker`, `squad:data`, etc. -- Moving a task between buckets = reassigning to a team member -- Task completion = 100% complete or move to "Done" bucket -- PRs and branches still go through the repo adapter (GitHub or Azure DevOps) - -### Prerequisites - -1. **Azure CLI** — `az login` -2. **Graph API access** — `az account get-access-token --resource-type ms-graph` -3. **Plan ID** — Found in the Planner URL or via Graph API - -### Configuration - -In `squad.config.ts`, specify the hybrid model: - -```typescript -const config: SquadConfig = { - // ... other config - platform: { - repo: 'azure-devops', // where code lives - workItems: 'planner', // where tasks live - planId: 'rYe_WFgqUUqnSTZfpMdKcZUAER1P', - }, -}; -``` - -### Ralph with Planner - -Ralph scans Planner tasks via the Microsoft Graph API instead of GitHub labels or ADO WIQL: - -``` -# List untriaged tasks -GET /planner/plans/{planId}/tasks → filter by "squad:untriaged" bucket - -# Assign to member (move to their bucket) -PATCH /planner/tasks/{taskId} → { "bucketId": "{squad:member bucket ID}" } -``` - -PR operations still use the repo adapter: - -``` -# Repo on Azure DevOps -az repos pr list --status active -az repos pr create --source-branch ... --target-branch ... - -# Repo on GitHub -gh pr list --state open -gh pr create --head ... --base ... -``` +# Enterprise Platforms + +Squad supports Azure DevOps and Microsoft Planner in addition to GitHub. When your git remote points to Azure DevOps, Squad automatically detects the platform and adapts its commands. For work-item tracking, Squad also supports a hybrid model where code lives in one platform and tasks live in Microsoft Planner. + +## Prerequisites + +1. **Azure CLI** — Install from [https://aka.ms/install-az-cli](https://aka.ms/install-az-cli) +2. **Azure DevOps extension** — `az extension add --name azure-devops` +3. **Login** — `az login` +4. **Set defaults** — `az devops configure --defaults organization=https://dev.azure.com/YOUR_ORG project=YOUR_PROJECT` + +Verify setup: + +```bash +az devops configure --list +# Should show organization and project +``` + +## How It Works + +Squad auto-detects the platform from your git remote URL: + +| Remote URL pattern | Detected platform | +|---|---| +| `github.com` | GitHub | +| `dev.azure.com` | Azure DevOps | +| `*.visualstudio.com` | Azure DevOps | +| `ssh.dev.azure.com` | Azure DevOps | + +## Differences from GitHub + +### Work Items vs Issues + +| GitHub | Azure DevOps | +|---|---| +| Issues | Work Items | +| Labels (e.g., `squad:alice`) | Tags (e.g., `squad:alice`) | +| `gh issue list --label X` | WIQL query via `az boards query` | +| `gh issue edit --add-label` | `az boards work-item update --fields "System.Tags=..."` | + +### Pull Requests + +| GitHub | Azure DevOps | +|---|---| +| `gh pr list` | `az repos pr list` | +| `gh pr create` | `az repos pr create` | +| `gh pr merge` | `az repos pr update --status completed` | +| Review: Approved / Changes Requested | Vote: 10 (approved) / -10 (rejected) | + +### Branch Operations + +Branch operations use the same `git` commands on both platforms. Squad creates branches with the naming convention `squad/{id}-{slug}`. + +## Ralph on Azure DevOps + +Ralph works identically on ADO — he scans for untriaged work items using WIQL queries instead of GitHub label filters: + +``` +# GitHub +gh issue list --label "squad:untriaged" --json number,title,labels + +# Azure DevOps +az boards query --wiql "SELECT [System.Id],[System.Title],[System.Tags] FROM WorkItems WHERE [System.Tags] Contains 'squad:untriaged'" +``` + +Tag assignment uses the same `squad:{member}` convention, stored as ADO work item tags separated by `;`. + +## Configuration + +Squad auto-detects ADO from the git remote URL. For basic use, no extra configuration is needed. + +### Work Item Configuration + +When your ADO environment has custom work item types, area paths, iterations, or when work items live in a **different project or org** than the git repo, configure the `ado` section in `.squad/config.json`: + +```json +{ + "version": 1, + "teamRoot": "/path/to/repo", + "platform": "azure-devops", + "ado": { + "org": "my-org", + "project": "my-work-items-project", + "defaultWorkItemType": "Scenario", + "areaPath": "MyProject\\Team Alpha", + "iterationPath": "MyProject\\Sprint 5" + } +} +``` + +| Field | Default | Description | +|-------|---------|-------------| +| `ado.org` | *(from git remote)* | ADO org for work items — set when work items are in a different org than the repo | +| `ado.project` | *(from git remote)* | ADO project for work items — set when work items are in a different project | +| `ado.defaultWorkItemType` | `"User Story"` | Default type for new work items. Some orgs use `"Scenario"`, `"Bug"`, or custom types | +| `ado.areaPath` | *(project default)* | Area path for new work items — controls which team's backlog they appear in | +| `ado.iterationPath` | *(project default)* | Iteration/sprint path — controls which sprint board work items appear on | + +All fields are optional. Omitted fields use the defaults shown above. + +### Authentication + +Squad uses the Azure CLI for ADO authentication — **no Personal Access Tokens (PATs) needed.** Run `az login` once, and Squad agents use your authenticated session for all operations. + +Alternatively, if the Azure DevOps MCP server is configured in your environment, Squad will use it automatically for richer API access. Add it to `.copilot/mcp-config.json`: + +```json +{ + "mcpServers": { + "azure-devops": { + "command": "npx", + "args": ["-y", "@azure/devops-mcp-server"] + } + } +} +``` + +Squad prefers MCP tools when available, falling back to `az` CLI when not. + +To explicitly check which platform Squad detects: + +```typescript +import { detectPlatform } from '@bradygaster/squad/platform'; + +const platform = detectPlatform('/path/to/repo'); +// Returns 'github', 'azure-devops', or 'planner' +``` + +--- + +## Microsoft Planner Support (Hybrid Model) + +Squad supports a hybrid model where your **repository** lives in GitHub or Azure DevOps, but **work items** are tracked in Microsoft Planner. This is common in enterprise environments where project management uses Planner while engineering uses ADO or GitHub for code. + +### How It Works + +- Planner **buckets** map to squad assignments: `squad:untriaged`, `squad:riker`, `squad:data`, etc. +- Moving a task between buckets = reassigning to a team member +- Task completion = 100% complete or move to "Done" bucket +- PRs and branches still go through the repo adapter (GitHub or Azure DevOps) + +### Prerequisites + +1. **Azure CLI** — `az login` +2. **Graph API access** — `az account get-access-token --resource-type ms-graph` +3. **Plan ID** — Found in the Planner URL or via Graph API + +### Configuration + +In `squad.config.ts`, specify the hybrid model: + +```typescript +const config: SquadConfig = { + // ... other config + platform: { + repo: 'azure-devops', // where code lives + workItems: 'planner', // where tasks live + planId: 'rYe_WFgqUUqnSTZfpMdKcZUAER1P', + }, +}; +``` + +### Ralph with Planner + +Ralph scans Planner tasks via the Microsoft Graph API instead of GitHub labels or ADO WIQL: + +``` +# List untriaged tasks +GET /planner/plans/{planId}/tasks → filter by "squad:untriaged" bucket + +# Assign to member (move to their bucket) +PATCH /planner/tasks/{taskId} → { "bucketId": "{squad:member bucket ID}" } +``` + +PR operations still use the repo adapter: + +``` +# Repo on Azure DevOps +az repos pr list --status active +az repos pr create --source-branch ... --target-branch ... + +# Repo on GitHub +gh pr list --state open +gh pr create --head ... --base ... +``` diff --git a/docs/features/export-import.md b/docs/src/content/docs/features/export-import.md similarity index 100% rename from docs/features/export-import.md rename to docs/src/content/docs/features/export-import.md diff --git a/docs/features/github-issues.md b/docs/src/content/docs/features/github-issues.md similarity index 100% rename from docs/features/github-issues.md rename to docs/src/content/docs/features/github-issues.md diff --git a/docs/features/gitlab-issues.md b/docs/src/content/docs/features/gitlab-issues.md similarity index 100% rename from docs/features/gitlab-issues.md rename to docs/src/content/docs/features/gitlab-issues.md diff --git a/docs/features/human-team-members.md b/docs/src/content/docs/features/human-team-members.md similarity index 100% rename from docs/features/human-team-members.md rename to docs/src/content/docs/features/human-team-members.md diff --git a/docs/features/labels.md b/docs/src/content/docs/features/labels.md similarity index 100% rename from docs/features/labels.md rename to docs/src/content/docs/features/labels.md diff --git a/docs/features/marketplace.md b/docs/src/content/docs/features/marketplace.md similarity index 100% rename from docs/features/marketplace.md rename to docs/src/content/docs/features/marketplace.md diff --git a/docs/features/mcp.md b/docs/src/content/docs/features/mcp.md similarity index 100% rename from docs/features/mcp.md rename to docs/src/content/docs/features/mcp.md diff --git a/docs/features/memory.md b/docs/src/content/docs/features/memory.md similarity index 100% rename from docs/features/memory.md rename to docs/src/content/docs/features/memory.md diff --git a/docs/features/model-selection.md b/docs/src/content/docs/features/model-selection.md similarity index 100% rename from docs/features/model-selection.md rename to docs/src/content/docs/features/model-selection.md diff --git a/docs/features/notifications.md b/docs/src/content/docs/features/notifications.md similarity index 100% rename from docs/features/notifications.md rename to docs/src/content/docs/features/notifications.md diff --git a/docs/features/parallel-execution.md b/docs/src/content/docs/features/parallel-execution.md similarity index 100% rename from docs/features/parallel-execution.md rename to docs/src/content/docs/features/parallel-execution.md diff --git a/docs/features/plugins.md b/docs/src/content/docs/features/plugins.md similarity index 100% rename from docs/features/plugins.md rename to docs/src/content/docs/features/plugins.md diff --git a/docs/features/prd-mode.md b/docs/src/content/docs/features/prd-mode.md similarity index 100% rename from docs/features/prd-mode.md rename to docs/src/content/docs/features/prd-mode.md diff --git a/docs/features/project-boards.md b/docs/src/content/docs/features/project-boards.md similarity index 100% rename from docs/features/project-boards.md rename to docs/src/content/docs/features/project-boards.md diff --git a/docs/features/ralph.md b/docs/src/content/docs/features/ralph.md similarity index 100% rename from docs/features/ralph.md rename to docs/src/content/docs/features/ralph.md diff --git a/docs/features/remote-control.md b/docs/src/content/docs/features/remote-control.md similarity index 95% rename from docs/features/remote-control.md rename to docs/src/content/docs/features/remote-control.md index 9e967911d..47ff15d6f 100644 --- a/docs/features/remote-control.md +++ b/docs/src/content/docs/features/remote-control.md @@ -1,326 +1,326 @@ -# Squad Remote Control - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -Control Copilot CLI from your phone via a secure WebSocket tunnel. Perfect for demos, pairing on mobile, or monitoring runs from anywhere. - -```bash -squad start --tunnel -# Shows QR code → scan with phone → terminal appears in browser -``` - ---- - -## What It Does - -`squad start` spawns Copilot CLI in a pseudo-terminal (PTY) and mirrors output to your phone in real-time via: - -1. **PTY** — Copilot runs in a full interactive terminal -2. **WebSocket server** — Terminal I/O streams live via WebSocket -3. **devtunnel** — Secure public URL with authentication (optional) -4. **Phone browser** — xterm.js terminal renders on your phone - -Architecture diagram: - -``` -[Copilot CLI in PTY] - ↓ (terminal output/input) -[WebSocket Server] - ↓ (bidirectional) -[devtunnel] (optional, provides public URL) - ↓ (HTTPS + private auth) -[Phone Browser (xterm.js)] - ↓ (mobile keyboard shortcuts, replay buffer) -[Your Phone] -``` - ---- - -## Prerequisites - -### Required - -- **devtunnel CLI** (for `--tunnel` mode) - ```bash - # Windows (winget) - winget install Microsoft.devtunnel - - # macOS (Homebrew) - brew install devtunnel - - # Or via GitHub releases - # https://github.com/microsoft/devtunnel/releases - ``` - -- **devtunnel authentication** (required before first use) - ```bash - devtunnel user login - # Browser opens → authenticate → success - ``` - -### Optional - -- **Node.js 18+** (for CLI) -- **Modern browser** on phone (iOS Safari, Chrome, Firefox) - ---- - -## Usage Examples - -### Basic: Local PTY Terminal - -No tunnel, no phone access — just run Copilot in a PTY: - -```bash -squad start -# Output: Started PTY terminal (PID: 12345) -# Copilot running locally -``` - -### With Phone Access (devtunnel + QR) - -Create a tunnel, show QR code, let your phone scan and connect: - -```bash -squad start --tunnel -# Output: Started devtunnel session -# Session ID: abc123xyz -# QR Code: [████████████████] -# URL: https://abc123xyz-dev.devtunnels.ms -# -# Tap or scan QR on your phone → terminal appears -``` - -Scan the QR code with your phone camera. Opens browser → terminal renders with xterm.js. - -### Custom Port - -Specify the WebSocket server port: - -```bash -squad start --port 3456 -# Output: WebSocket listening on localhost:3456 -# Access via: ws://localhost:3456 -``` - -### Custom Command - -Run a different shell or program instead of copilot: - -```bash -squad start --tunnel --command powershell -squad start --tunnel --command "python" -squad start --tunnel --command "bash -i" -``` - -### Pass Copilot Flags Through - -All flags after `--tunnel` pass to copilot: - -```bash -squad start --tunnel --yolo -squad start --tunnel --model gpt-4 -squad start --tunnel --no-config -``` - ---- - -## Security Model - -Remote access has **7 layers** of security: - -### 1. **devtunnel Private Auth** -- URL requires `Authorization` header (devtunnel access token) -- Tunnel is private by default — no public discovery - -### 2. **Session Token (UUID, 4-hour TTL)** -- Each session gets a unique token, valid for 4 hours -- Token embedded in QR code or shown as connection string -- Expires automatically - -### 3. **Ticket-Based WebSocket Auth** -- First request exchanges session token for single-use ticket -- Ticket valid 60 seconds, single use only -- Prevents token replay attacks - -### 4. **HTTP Rate Limiting** -- 30 requests per minute per IP address -- Blocks brute-force connection attempts -- Rate limit resets hourly - -### 5. **Environment Variable Blocklist** -- 27 common secret patterns redacted from output -- Blocks: `PASSWORD`, `TOKEN`, `SECRET`, `KEY`, `AWS_`, `GITHUB_`, `API_KEY`, etc. -- ANSI escape sequences cannot bypass redaction - -### 6. **Secret Redaction (27 Patterns + ANSI Bypass Prevention)** -- Secrets matching patterns replaced with `[REDACTED]` -- ANSI codes cannot hide redaction logic -- Example: `Password=mysecret123` → `Password=[REDACTED]` - -### 7. **Connection Limits** -- **Global:** Max 5 concurrent phone connections per session -- **Per IP:** Max 2 concurrent connections per IP address -- Excess connections rejected with 429 (Too Many Requests) - ---- - -## Mobile Keyboard - -When your phone connects, a key bar appears below the terminal: - -| Key | Action | -|-----|--------| -| **↑** / **↓** | Scroll history / scroll terminal output | -| **←** / **→** | Move cursor left / right | -| **Tab** | Insert tab character (or autocomplete if supported) | -| **Enter** | Send command / newline | -| **Esc** | Send Escape key (menu mode, cancel) | -| **Ctrl+C** | Send interrupt signal (SIGINT) — kills running command | -| **Space** | Insert space | -| **⌫** | Backspace / delete | - ---- - -## Replay Buffer - -When a new phone joins the session: - -1. **Terminal history is replayed** — joins don't see a blank screen -2. **Replay window** — last 1000 lines of terminal output -3. **Scrollback included** — can scroll to see previous commands - -This means late-joiners see context, not blank canvas. - ---- - -## Session Dashboard - -List and manage active devtunnel sessions: - -```bash -squad start --list-sessions -# Output: -# Session 1: abc123xyz (2 phones connected, 1h 23m running) -# Session 2: def456uvw (0 phones, 2m running) -# Session 3: ghi789rst (1 phone, idle) -``` - -Kill a session: - -```bash -squad start --kill-session abc123xyz -# Output: Session closed. Remaining: 2 -``` - ---- - -## Architecture Notes - -### PTY-Only Mode - -Remote Control runs in **PTY-only mode** — no Copilot ACP (Agent Control Protocol) messages flow through the WebSocket. The terminal is a **mirror**, not a command channel: - -- Terminal I/O (text, control codes) ↔ WebSocket -- ACP protocol stays local to the Copilot process -- No agent instructions flow through the tunnel - -This design keeps the tunnel stateless and reduces surface area. - ---- - -## Audit Logging - -All connections, authentication, and security events are logged: - -```bash -~/.cli-tunnel/audit/squad-audit-2025-01-15.jsonl -``` - -Each line is a JSON object: - -```json -{ - "timestamp": "2025-01-15T10:23:45.123Z", - "event": "connection", - "session_id": "abc123xyz", - "phone_ip": "203.0.113.42", - "status": "authenticated" -} -``` - -Events logged: -- `connection` — Phone connected -- `disconnection` — Phone disconnected -- `auth_failure` — Token/ticket validation failed -- `rate_limit` — Rate limit exceeded -- `redaction` — Secret pattern matched and redacted -- `command` — Command executed (summary, no args) - -Rotate daily, keep 30 days by default. - ---- - -## Troubleshooting - -### "devtunnel not found" - -Install devtunnel: - -```bash -winget install Microsoft.devtunnel -``` - -Or check `PATH`: - -```bash -where devtunnel -# Should show path to executable -``` - -### "Not authenticated to devtunnel" - -Log in: - -```bash -devtunnel user login -``` - -### Phone doesn't connect (QR code error) - -1. Check QR code isn't expired (valid for 5 minutes) -2. Verify phone is on same network or has internet -3. Try manual URL instead of QR: - ```bash - # Copy URL from terminal and paste in phone browser - https://abc123xyz-dev.devtunnels.ms - ``` - -### Terminal freezes - -This is typically Copilot waiting for input. Type a command or press Enter: - -``` -squad > [CURSOR BLINKING] -``` - -Press Enter to see the prompt. - -### Audit logs missing - -Ensure `~/.cli-tunnel/` directory exists: - -```bash -mkdir -p ~/.cli-tunnel/audit -``` - -Logs are created on first event. - ---- - -## See Also - -- [CLI Reference](../reference/cli.md) — All commands -- [Getting Started](../get-started/installation.md) — Squad setup -- [VS Code Integration](./vscode.md) — Remote Control in VS Code +# Squad Remote Control + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + + +Control Copilot CLI from your phone via a secure WebSocket tunnel. Perfect for demos, pairing on mobile, or monitoring runs from anywhere. + +```bash +squad start --tunnel +# Shows QR code → scan with phone → terminal appears in browser +``` + +--- + +## What It Does + +`squad start` spawns Copilot CLI in a pseudo-terminal (PTY) and mirrors output to your phone in real-time via: + +1. **PTY** — Copilot runs in a full interactive terminal +2. **WebSocket server** — Terminal I/O streams live via WebSocket +3. **devtunnel** — Secure public URL with authentication (optional) +4. **Phone browser** — xterm.js terminal renders on your phone + +Architecture diagram: + +``` +[Copilot CLI in PTY] + ↓ (terminal output/input) +[WebSocket Server] + ↓ (bidirectional) +[devtunnel] (optional, provides public URL) + ↓ (HTTPS + private auth) +[Phone Browser (xterm.js)] + ↓ (mobile keyboard shortcuts, replay buffer) +[Your Phone] +``` + +--- + +## Prerequisites + +### Required + +- **devtunnel CLI** (for `--tunnel` mode) + ```bash + # Windows (winget) + winget install Microsoft.devtunnel + + # macOS (Homebrew) + brew install devtunnel + + # Or via GitHub releases + # https://github.com/microsoft/devtunnel/releases + ``` + +- **devtunnel authentication** (required before first use) + ```bash + devtunnel user login + # Browser opens → authenticate → success + ``` + +### Optional + +- **Node.js 18+** (for CLI) +- **Modern browser** on phone (iOS Safari, Chrome, Firefox) + +--- + +## Usage Examples + +### Basic: Local PTY Terminal + +No tunnel, no phone access — just run Copilot in a PTY: + +```bash +squad start +# Output: Started PTY terminal (PID: 12345) +# Copilot running locally +``` + +### With Phone Access (devtunnel + QR) + +Create a tunnel, show QR code, let your phone scan and connect: + +```bash +squad start --tunnel +# Output: Started devtunnel session +# Session ID: abc123xyz +# QR Code: [████████████████] +# URL: https://abc123xyz-dev.devtunnels.ms +# +# Tap or scan QR on your phone → terminal appears +``` + +Scan the QR code with your phone camera. Opens browser → terminal renders with xterm.js. + +### Custom Port + +Specify the WebSocket server port: + +```bash +squad start --port 3456 +# Output: WebSocket listening on localhost:3456 +# Access via: ws://localhost:3456 +``` + +### Custom Command + +Run a different shell or program instead of copilot: + +```bash +squad start --tunnel --command powershell +squad start --tunnel --command "python" +squad start --tunnel --command "bash -i" +``` + +### Pass Copilot Flags Through + +All flags after `--tunnel` pass to copilot: + +```bash +squad start --tunnel --yolo +squad start --tunnel --model gpt-4 +squad start --tunnel --no-config +``` + +--- + +## Security Model + +Remote access has **7 layers** of security: + +### 1. **devtunnel Private Auth** +- URL requires `Authorization` header (devtunnel access token) +- Tunnel is private by default — no public discovery + +### 2. **Session Token (UUID, 4-hour TTL)** +- Each session gets a unique token, valid for 4 hours +- Token embedded in QR code or shown as connection string +- Expires automatically + +### 3. **Ticket-Based WebSocket Auth** +- First request exchanges session token for single-use ticket +- Ticket valid 60 seconds, single use only +- Prevents token replay attacks + +### 4. **HTTP Rate Limiting** +- 30 requests per minute per IP address +- Blocks brute-force connection attempts +- Rate limit resets hourly + +### 5. **Environment Variable Blocklist** +- 27 common secret patterns redacted from output +- Blocks: `PASSWORD`, `TOKEN`, `SECRET`, `KEY`, `AWS_`, `GITHUB_`, `API_KEY`, etc. +- ANSI escape sequences cannot bypass redaction + +### 6. **Secret Redaction (27 Patterns + ANSI Bypass Prevention)** +- Secrets matching patterns replaced with `[REDACTED]` +- ANSI codes cannot hide redaction logic +- Example: `Password=mysecret123` → `Password=[REDACTED]` + +### 7. **Connection Limits** +- **Global:** Max 5 concurrent phone connections per session +- **Per IP:** Max 2 concurrent connections per IP address +- Excess connections rejected with 429 (Too Many Requests) + +--- + +## Mobile Keyboard + +When your phone connects, a key bar appears below the terminal: + +| Key | Action | +|-----|--------| +| **↑** / **↓** | Scroll history / scroll terminal output | +| **←** / **→** | Move cursor left / right | +| **Tab** | Insert tab character (or autocomplete if supported) | +| **Enter** | Send command / newline | +| **Esc** | Send Escape key (menu mode, cancel) | +| **Ctrl+C** | Send interrupt signal (SIGINT) — kills running command | +| **Space** | Insert space | +| **⌫** | Backspace / delete | + +--- + +## Replay Buffer + +When a new phone joins the session: + +1. **Terminal history is replayed** — joins don't see a blank screen +2. **Replay window** — last 1000 lines of terminal output +3. **Scrollback included** — can scroll to see previous commands + +This means late-joiners see context, not blank canvas. + +--- + +## Session Dashboard + +List and manage active devtunnel sessions: + +```bash +squad start --list-sessions +# Output: +# Session 1: abc123xyz (2 phones connected, 1h 23m running) +# Session 2: def456uvw (0 phones, 2m running) +# Session 3: ghi789rst (1 phone, idle) +``` + +Kill a session: + +```bash +squad start --kill-session abc123xyz +# Output: Session closed. Remaining: 2 +``` + +--- + +## Architecture Notes + +### PTY-Only Mode + +Remote Control runs in **PTY-only mode** — no Copilot ACP (Agent Control Protocol) messages flow through the WebSocket. The terminal is a **mirror**, not a command channel: + +- Terminal I/O (text, control codes) ↔ WebSocket +- ACP protocol stays local to the Copilot process +- No agent instructions flow through the tunnel + +This design keeps the tunnel stateless and reduces surface area. + +--- + +## Audit Logging + +All connections, authentication, and security events are logged: + +```bash +~/.cli-tunnel/audit/squad-audit-2025-01-15.jsonl +``` + +Each line is a JSON object: + +```json +{ + "timestamp": "2025-01-15T10:23:45.123Z", + "event": "connection", + "session_id": "abc123xyz", + "phone_ip": "203.0.113.42", + "status": "authenticated" +} +``` + +Events logged: +- `connection` — Phone connected +- `disconnection` — Phone disconnected +- `auth_failure` — Token/ticket validation failed +- `rate_limit` — Rate limit exceeded +- `redaction` — Secret pattern matched and redacted +- `command` — Command executed (summary, no args) + +Rotate daily, keep 30 days by default. + +--- + +## Troubleshooting + +### "devtunnel not found" + +Install devtunnel: + +```bash +winget install Microsoft.devtunnel +``` + +Or check `PATH`: + +```bash +where devtunnel +# Should show path to executable +``` + +### "Not authenticated to devtunnel" + +Log in: + +```bash +devtunnel user login +``` + +### Phone doesn't connect (QR code error) + +1. Check QR code isn't expired (valid for 5 minutes) +2. Verify phone is on same network or has internet +3. Try manual URL instead of QR: + ```bash + # Copy URL from terminal and paste in phone browser + https://abc123xyz-dev.devtunnels.ms + ``` + +### Terminal freezes + +This is typically Copilot waiting for input. Type a command or press Enter: + +``` +squad > [CURSOR BLINKING] +``` + +Press Enter to see the prompt. + +### Audit logs missing + +Ensure `~/.cli-tunnel/` directory exists: + +```bash +mkdir -p ~/.cli-tunnel/audit +``` + +Logs are created on first event. + +--- + +## See Also + +- [CLI Reference](../reference/cli.md) — All commands +- [Getting Started](../get-started/installation.md) — Squad setup +- [VS Code Integration](./vscode.md) — Remote Control in VS Code diff --git a/docs/features/response-modes.md b/docs/src/content/docs/features/response-modes.md similarity index 100% rename from docs/features/response-modes.md rename to docs/src/content/docs/features/response-modes.md diff --git a/docs/features/reviewer-protocol.md b/docs/src/content/docs/features/reviewer-protocol.md similarity index 100% rename from docs/features/reviewer-protocol.md rename to docs/src/content/docs/features/reviewer-protocol.md diff --git a/docs/features/routing.md b/docs/src/content/docs/features/routing.md similarity index 100% rename from docs/features/routing.md rename to docs/src/content/docs/features/routing.md diff --git a/docs/features/skills.md b/docs/src/content/docs/features/skills.md similarity index 100% rename from docs/features/skills.md rename to docs/src/content/docs/features/skills.md diff --git a/docs/features/squad-rc.md b/docs/src/content/docs/features/squad-rc.md similarity index 100% rename from docs/features/squad-rc.md rename to docs/src/content/docs/features/squad-rc.md diff --git a/docs/features/streams.md b/docs/src/content/docs/features/streams.md similarity index 97% rename from docs/features/streams.md rename to docs/src/content/docs/features/streams.md index e02fa803b..0b2cf6b46 100644 --- a/docs/features/streams.md +++ b/docs/src/content/docs/features/streams.md @@ -1,148 +1,148 @@ -# Squad SubSquads - -> Scale Squad across multiple Codespaces by partitioning work into labeled SubSquads. - -## What Are SubSquads? - -A **SubSquad** is a named partition of work within a Squad project. Each SubSquad targets a specific GitHub label (e.g., `team:ui`, `team:backend`) and optionally restricts agents to certain directories. Multiple Squad instances — each running in its own Codespace — can each activate a different SubSquad, enabling parallel work across teams. - -## Why SubSquads? - -Squad was originally designed for a single team per repository. As projects grow, a single Codespace becomes a bottleneck: - -- **Model rate limits** — One Codespace hitting API limits slows the whole team -- **Context overload** — Ralph picks up all issues, not just the relevant ones -- **Folder conflicts** — Multiple agents editing the same files causes merge pain - -SubSquads solve this by giving each Codespace a scoped view of the project. - -## Configuration - -### 1. Create `.squad/streams.json` - -```json -{ - "workstreams": [ - { - "name": "ui-team", - "labelFilter": "team:ui", - "folderScope": ["apps/web", "packages/ui"], - "workflow": "branch-per-issue", - "description": "Frontend team — React, CSS, components" - }, - { - "name": "backend-team", - "labelFilter": "team:backend", - "folderScope": ["apps/api", "packages/core"], - "workflow": "branch-per-issue", - "description": "Backend team — APIs, database, services" - }, - { - "name": "infra-team", - "labelFilter": "team:infra", - "folderScope": [".github", "infrastructure"], - "workflow": "direct", - "description": "Infrastructure — CI/CD, deployment, monitoring" - } - ], - "defaultWorkflow": "branch-per-issue" -} -``` - -### 2. Activate a SubSquad - -There are three ways to tell Squad which SubSquad to use: - -#### Environment Variable (recommended for Codespaces) - -```bash -export SQUAD_TEAM=ui-team -``` - -Set this in your Codespace's environment or devcontainer.json: - -```json -{ - "containerEnv": { - "SQUAD_TEAM": "ui-team" - } -} -``` - -#### .squad-workstream File (local activation) - -```bash -squad subsquads activate ui-team -``` - -This writes a `.squad-workstream` file (gitignored) so the setting is local to your machine. - -#### Auto-select (single SubSquad) - -If `streams.json` contains only one SubSquad, it's automatically selected. - -### 3. Resolution Priority - -1. `SQUAD_TEAM` env var (highest) -2. `.squad-workstream` file -3. Single-SubSquad auto-select -4. No SubSquad (classic single-squad mode) - -## SubSquad Definition Fields - -| Field | Required | Description | -|-------|----------|-------------| -| `name` | Yes | Unique SubSquad identifier (kebab-case) | -| `labelFilter` | Yes | GitHub label to filter issues | -| `folderScope` | No | Directories this SubSquad may modify | -| `workflow` | No | `branch-per-issue` (default) or `direct` | -| `description` | No | Human-readable purpose | - -## CLI Reference - -```bash -# List configured SubSquads -squad subsquads list - -# Show SubSquad activity (branches, PRs) -squad subsquads status - -# Activate a SubSquad locally -squad subsquads activate -``` - -> **Note:** `squad workstreams` and `squad streams` are deprecated aliases for `squad subsquads`. - -## How It Works - -### Triage (Ralph) - -When a SubSquad is active, Ralph's triage only picks up issues labeled with the SubSquad's `labelFilter`. Unmatched issues are left for other SubSquads or the main squad. - -### Workflow Enforcement - -- **branch-per-issue** (default): Every issue gets its own branch and PR. Agents never commit directly to main. -- **direct**: Agents may commit directly (useful for infra/ops SubSquads). - -### Folder Scope - -When `folderScope` is set, agents should primarily modify files within those directories. However, `folderScope` is **advisory, not a hard lock** — agents may still touch shared files (types, configs, package exports) when their issue requires it. The real protection comes from `branch-per-issue` workflow: each issue gets its own branch, so two SubSquads editing the same file won't conflict until merge time. - -> **Tip:** If two SubSquads' PRs touch the same file, Git resolves non-overlapping changes automatically. For semantic conflicts (incompatible API changes), use PR review to catch them. - -### Cost Optimization: Single-Machine Multi-SubSquad - -You don't need a separate Codespace per SubSquad. One machine can serve multiple SubSquads: - -```bash -# Switch between SubSquads manually -squad subsquads activate ui-team # Ralph works team:ui issues -# ... later ... -squad subsquads activate backend-team # now works team:backend issues -``` - -This gives you 1× Codespace cost instead of N×, at the expense of serial (not parallel) execution. Each issue still gets its own branch — no conflicts. - -## Example: Multi-Codespace Setup - -See [Multi-Codespace Scenario](../scenarios/multi-codespace.md) for a complete walkthrough. +# Squad SubSquads + +> Scale Squad across multiple Codespaces by partitioning work into labeled SubSquads. + +## What Are SubSquads? + +A **SubSquad** is a named partition of work within a Squad project. Each SubSquad targets a specific GitHub label (e.g., `team:ui`, `team:backend`) and optionally restricts agents to certain directories. Multiple Squad instances — each running in its own Codespace — can each activate a different SubSquad, enabling parallel work across teams. + +## Why SubSquads? + +Squad was originally designed for a single team per repository. As projects grow, a single Codespace becomes a bottleneck: + +- **Model rate limits** — One Codespace hitting API limits slows the whole team +- **Context overload** — Ralph picks up all issues, not just the relevant ones +- **Folder conflicts** — Multiple agents editing the same files causes merge pain + +SubSquads solve this by giving each Codespace a scoped view of the project. + +## Configuration + +### 1. Create `.squad/streams.json` + +```json +{ + "workstreams": [ + { + "name": "ui-team", + "labelFilter": "team:ui", + "folderScope": ["apps/web", "packages/ui"], + "workflow": "branch-per-issue", + "description": "Frontend team — React, CSS, components" + }, + { + "name": "backend-team", + "labelFilter": "team:backend", + "folderScope": ["apps/api", "packages/core"], + "workflow": "branch-per-issue", + "description": "Backend team — APIs, database, services" + }, + { + "name": "infra-team", + "labelFilter": "team:infra", + "folderScope": [".github", "infrastructure"], + "workflow": "direct", + "description": "Infrastructure — CI/CD, deployment, monitoring" + } + ], + "defaultWorkflow": "branch-per-issue" +} +``` + +### 2. Activate a SubSquad + +There are three ways to tell Squad which SubSquad to use: + +#### Environment Variable (recommended for Codespaces) + +```bash +export SQUAD_TEAM=ui-team +``` + +Set this in your Codespace's environment or devcontainer.json: + +```json +{ + "containerEnv": { + "SQUAD_TEAM": "ui-team" + } +} +``` + +#### .squad-workstream File (local activation) + +```bash +squad subsquads activate ui-team +``` + +This writes a `.squad-workstream` file (gitignored) so the setting is local to your machine. + +#### Auto-select (single SubSquad) + +If `streams.json` contains only one SubSquad, it's automatically selected. + +### 3. Resolution Priority + +1. `SQUAD_TEAM` env var (highest) +2. `.squad-workstream` file +3. Single-SubSquad auto-select +4. No SubSquad (classic single-squad mode) + +## SubSquad Definition Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | Yes | Unique SubSquad identifier (kebab-case) | +| `labelFilter` | Yes | GitHub label to filter issues | +| `folderScope` | No | Directories this SubSquad may modify | +| `workflow` | No | `branch-per-issue` (default) or `direct` | +| `description` | No | Human-readable purpose | + +## CLI Reference + +```bash +# List configured SubSquads +squad subsquads list + +# Show SubSquad activity (branches, PRs) +squad subsquads status + +# Activate a SubSquad locally +squad subsquads activate +``` + +> **Note:** `squad workstreams` and `squad streams` are deprecated aliases for `squad subsquads`. + +## How It Works + +### Triage (Ralph) + +When a SubSquad is active, Ralph's triage only picks up issues labeled with the SubSquad's `labelFilter`. Unmatched issues are left for other SubSquads or the main squad. + +### Workflow Enforcement + +- **branch-per-issue** (default): Every issue gets its own branch and PR. Agents never commit directly to main. +- **direct**: Agents may commit directly (useful for infra/ops SubSquads). + +### Folder Scope + +When `folderScope` is set, agents should primarily modify files within those directories. However, `folderScope` is **advisory, not a hard lock** — agents may still touch shared files (types, configs, package exports) when their issue requires it. The real protection comes from `branch-per-issue` workflow: each issue gets its own branch, so two SubSquads editing the same file won't conflict until merge time. + +> **Tip:** If two SubSquads' PRs touch the same file, Git resolves non-overlapping changes automatically. For semantic conflicts (incompatible API changes), use PR review to catch them. + +### Cost Optimization: Single-Machine Multi-SubSquad + +You don't need a separate Codespace per SubSquad. One machine can serve multiple SubSquads: + +```bash +# Switch between SubSquads manually +squad subsquads activate ui-team # Ralph works team:ui issues +# ... later ... +squad subsquads activate backend-team # now works team:backend issues +``` + +This gives you 1× Codespace cost instead of N×, at the expense of serial (not parallel) execution. Each issue still gets its own branch — no conflicts. + +## Example: Multi-Codespace Setup + +See [Multi-Codespace Scenario](../scenarios/multi-codespace.md) for a complete walkthrough. diff --git a/docs/features/team-setup.md b/docs/src/content/docs/features/team-setup.md similarity index 100% rename from docs/features/team-setup.md rename to docs/src/content/docs/features/team-setup.md diff --git a/docs/features/upstream-inheritance.md b/docs/src/content/docs/features/upstream-inheritance.md similarity index 100% rename from docs/features/upstream-inheritance.md rename to docs/src/content/docs/features/upstream-inheritance.md diff --git a/docs/features/vscode.md b/docs/src/content/docs/features/vscode.md similarity index 100% rename from docs/features/vscode.md rename to docs/src/content/docs/features/vscode.md diff --git a/docs/features/worktrees.md b/docs/src/content/docs/features/worktrees.md similarity index 100% rename from docs/features/worktrees.md rename to docs/src/content/docs/features/worktrees.md diff --git a/docs/get-started/first-session.md b/docs/src/content/docs/get-started/first-session.md similarity index 100% rename from docs/get-started/first-session.md rename to docs/src/content/docs/get-started/first-session.md diff --git a/docs/get-started/installation.md b/docs/src/content/docs/get-started/installation.md similarity index 100% rename from docs/get-started/installation.md rename to docs/src/content/docs/get-started/installation.md diff --git a/docs/get-started/migration.md b/docs/src/content/docs/get-started/migration.md similarity index 100% rename from docs/get-started/migration.md rename to docs/src/content/docs/get-started/migration.md diff --git a/docs/guide.md b/docs/src/content/docs/guide.md similarity index 100% rename from docs/guide.md rename to docs/src/content/docs/guide.md diff --git a/docs/guide/contributing.md b/docs/src/content/docs/guide/contributing.md similarity index 100% rename from docs/guide/contributing.md rename to docs/src/content/docs/guide/contributing.md diff --git a/docs/guide/contributors.md b/docs/src/content/docs/guide/contributors.md similarity index 100% rename from docs/guide/contributors.md rename to docs/src/content/docs/guide/contributors.md diff --git a/docs/guide/personal-squad.md b/docs/src/content/docs/guide/personal-squad.md similarity index 100% rename from docs/guide/personal-squad.md rename to docs/src/content/docs/guide/personal-squad.md diff --git a/docs/guide/sample-prompts.md b/docs/src/content/docs/guide/sample-prompts.md similarity index 100% rename from docs/guide/sample-prompts.md rename to docs/src/content/docs/guide/sample-prompts.md diff --git a/docs/guide/tips-and-tricks.md b/docs/src/content/docs/guide/tips-and-tricks.md similarity index 100% rename from docs/guide/tips-and-tricks.md rename to docs/src/content/docs/guide/tips-and-tricks.md diff --git a/docs/insider-program.md b/docs/src/content/docs/insider-program.md similarity index 100% rename from docs/insider-program.md rename to docs/src/content/docs/insider-program.md diff --git a/docs/reference/cli.md b/docs/src/content/docs/reference/cli.md similarity index 100% rename from docs/reference/cli.md rename to docs/src/content/docs/reference/cli.md diff --git a/docs/reference/config.md b/docs/src/content/docs/reference/config.md similarity index 100% rename from docs/reference/config.md rename to docs/src/content/docs/reference/config.md diff --git a/docs/reference/sdk.md b/docs/src/content/docs/reference/sdk.md similarity index 100% rename from docs/reference/sdk.md rename to docs/src/content/docs/reference/sdk.md diff --git a/docs/sample-prompts.md b/docs/src/content/docs/sample-prompts.md similarity index 100% rename from docs/sample-prompts.md rename to docs/src/content/docs/sample-prompts.md diff --git a/docs/scenarios/aspire-dashboard.md b/docs/src/content/docs/scenarios/aspire-dashboard.md similarity index 100% rename from docs/scenarios/aspire-dashboard.md rename to docs/src/content/docs/scenarios/aspire-dashboard.md diff --git a/docs/scenarios/ci-cd-integration.md b/docs/src/content/docs/scenarios/ci-cd-integration.md similarity index 100% rename from docs/scenarios/ci-cd-integration.md rename to docs/src/content/docs/scenarios/ci-cd-integration.md diff --git a/docs/scenarios/client-compatibility.md b/docs/src/content/docs/scenarios/client-compatibility.md similarity index 100% rename from docs/scenarios/client-compatibility.md rename to docs/src/content/docs/scenarios/client-compatibility.md diff --git a/docs/scenarios/disaster-recovery.md b/docs/src/content/docs/scenarios/disaster-recovery.md similarity index 100% rename from docs/scenarios/disaster-recovery.md rename to docs/src/content/docs/scenarios/disaster-recovery.md diff --git a/docs/scenarios/existing-repo.md b/docs/src/content/docs/scenarios/existing-repo.md similarity index 100% rename from docs/scenarios/existing-repo.md rename to docs/src/content/docs/scenarios/existing-repo.md diff --git a/docs/scenarios/issue-driven-dev.md b/docs/src/content/docs/scenarios/issue-driven-dev.md similarity index 100% rename from docs/scenarios/issue-driven-dev.md rename to docs/src/content/docs/scenarios/issue-driven-dev.md diff --git a/docs/scenarios/keep-my-squad.md b/docs/src/content/docs/scenarios/keep-my-squad.md similarity index 100% rename from docs/scenarios/keep-my-squad.md rename to docs/src/content/docs/scenarios/keep-my-squad.md diff --git a/docs/scenarios/large-codebase.md b/docs/src/content/docs/scenarios/large-codebase.md similarity index 100% rename from docs/scenarios/large-codebase.md rename to docs/src/content/docs/scenarios/large-codebase.md diff --git a/docs/scenarios/mid-project.md b/docs/src/content/docs/scenarios/mid-project.md similarity index 100% rename from docs/scenarios/mid-project.md rename to docs/src/content/docs/scenarios/mid-project.md diff --git a/docs/scenarios/monorepo.md b/docs/src/content/docs/scenarios/monorepo.md similarity index 100% rename from docs/scenarios/monorepo.md rename to docs/src/content/docs/scenarios/monorepo.md diff --git a/docs/scenarios/multi-codespace.md b/docs/src/content/docs/scenarios/multi-codespace.md similarity index 96% rename from docs/scenarios/multi-codespace.md rename to docs/src/content/docs/scenarios/multi-codespace.md index 93315c3ac..a3aef751b 100644 --- a/docs/scenarios/multi-codespace.md +++ b/docs/src/content/docs/scenarios/multi-codespace.md @@ -1,127 +1,127 @@ -# Multi-Codespace Setup with Squad SubSquads - -> End-to-end walkthrough of running multiple Squad instances across Codespaces. - -## Background: The Tetris Experiment - -We validated Squad SubSquads by building a multiplayer Tetris game using 3 Codespaces, each running a separate SubSquad: - -| Codespace | SubSquad | Label | Focus | -|-----------|--------|-------|-------| -| CS-1 | `ui-team` | `team:ui` | React game board, piece rendering, animations | -| CS-2 | `backend-team` | `team:backend` | WebSocket server, game state, matchmaking | -| CS-3 | `infra-team` | `team:infra` | CI/CD, Docker, deployment | - -All three Codespaces shared the same repository. Each Squad instance only picked up issues matching its SubSquad's label. - -## Setup Steps - -### 1. Create the SubSquads config - -In your repository, create `.squad/streams.json`: - -```json -{ - "workstreams": [ - { - "name": "ui-team", - "labelFilter": "team:ui", - "folderScope": ["src/client", "src/components"], - "description": "Game UI and rendering" - }, - { - "name": "backend-team", - "labelFilter": "team:backend", - "folderScope": ["src/server", "src/shared"], - "description": "Game server and state management" - }, - { - "name": "infra-team", - "labelFilter": "team:infra", - "folderScope": [".github", "docker", "k8s"], - "workflow": "direct", - "description": "Build and deploy pipeline" - } - ], - "defaultWorkflow": "branch-per-issue" -} -``` - -### 2. Configure each Codespace - -In `.devcontainer/devcontainer.json`, set the `SQUAD_TEAM` env var. For multiple configs, use [devcontainer features](https://containers.dev/features) or separate devcontainer folders: - -**Option A: Separate devcontainer configs** - -``` -.devcontainer/ - ui-team/ - devcontainer.json # SQUAD_TEAM=ui-team - backend-team/ - devcontainer.json # SQUAD_TEAM=backend-team - infra-team/ - devcontainer.json # SQUAD_TEAM=infra-team -``` - -**Option B: Set env var after launch** - -```bash -export SQUAD_TEAM=ui-team -squad # launches with SubSquad context -``` - -### 3. Label your issues - -Create GitHub issues with the appropriate team labels: - -```bash -gh issue create --title "Add piece rotation animation" --label "team:ui" -gh issue create --title "Implement matchmaking queue" --label "team:backend" -gh issue create --title "Add Docker compose for dev" --label "team:infra" -``` - -### 4. Launch Squad in each Codespace - -Each Codespace runs `squad` normally. The SubSquad context is detected automatically: - -```bash -# In Codespace 1 (SQUAD_TEAM=ui-team) -squad -# → Ralph only triages issues labeled "team:ui" -# → Agents only modify files in src/client, src/components - -# In Codespace 2 (SQUAD_TEAM=backend-team) -squad -# → Ralph only triages issues labeled "team:backend" -# → Agents only modify files in src/server, src/shared -``` - -### 5. Monitor across SubSquads - -Use the CLI from any Codespace to see all SubSquads: - -```bash -squad subsquads status -``` - - - - -## What Worked - -- **Clear separation**: Each SubSquad had well-defined boundaries, minimizing merge conflicts -- **Parallel velocity**: 3x throughput vs. single-squad mode for independent work -- **Label-based routing**: Simple, uses existing GitHub infrastructure - -## What Didn't Work (Yet) - -- **Cross-SubSquad dependencies**: When the UI team needed a backend API change, manual coordination was required -- **Shared files**: `package.json`, `tsconfig.json`, and other root files caused occasional conflicts -- **No meta-coordinator**: No automated way to coordinate across SubSquads (future work) - -## Lessons Learned - -1. **Keep SubSquads independent** — design folder boundaries to minimize shared files -2. **Use branch-per-issue** — direct commits across SubSquads cause merge hell -3. **Label everything** — unlabeled issues get lost between SubSquads -4. **Start with 2 SubSquads** — add more once the team finds its rhythm +# Multi-Codespace Setup with Squad SubSquads + +> End-to-end walkthrough of running multiple Squad instances across Codespaces. + +## Background: The Tetris Experiment + +We validated Squad SubSquads by building a multiplayer Tetris game using 3 Codespaces, each running a separate SubSquad: + +| Codespace | SubSquad | Label | Focus | +|-----------|--------|-------|-------| +| CS-1 | `ui-team` | `team:ui` | React game board, piece rendering, animations | +| CS-2 | `backend-team` | `team:backend` | WebSocket server, game state, matchmaking | +| CS-3 | `infra-team` | `team:infra` | CI/CD, Docker, deployment | + +All three Codespaces shared the same repository. Each Squad instance only picked up issues matching its SubSquad's label. + +## Setup Steps + +### 1. Create the SubSquads config + +In your repository, create `.squad/streams.json`: + +```json +{ + "workstreams": [ + { + "name": "ui-team", + "labelFilter": "team:ui", + "folderScope": ["src/client", "src/components"], + "description": "Game UI and rendering" + }, + { + "name": "backend-team", + "labelFilter": "team:backend", + "folderScope": ["src/server", "src/shared"], + "description": "Game server and state management" + }, + { + "name": "infra-team", + "labelFilter": "team:infra", + "folderScope": [".github", "docker", "k8s"], + "workflow": "direct", + "description": "Build and deploy pipeline" + } + ], + "defaultWorkflow": "branch-per-issue" +} +``` + +### 2. Configure each Codespace + +In `.devcontainer/devcontainer.json`, set the `SQUAD_TEAM` env var. For multiple configs, use [devcontainer features](https://containers.dev/features) or separate devcontainer folders: + +**Option A: Separate devcontainer configs** + +``` +.devcontainer/ + ui-team/ + devcontainer.json # SQUAD_TEAM=ui-team + backend-team/ + devcontainer.json # SQUAD_TEAM=backend-team + infra-team/ + devcontainer.json # SQUAD_TEAM=infra-team +``` + +**Option B: Set env var after launch** + +```bash +export SQUAD_TEAM=ui-team +squad # launches with SubSquad context +``` + +### 3. Label your issues + +Create GitHub issues with the appropriate team labels: + +```bash +gh issue create --title "Add piece rotation animation" --label "team:ui" +gh issue create --title "Implement matchmaking queue" --label "team:backend" +gh issue create --title "Add Docker compose for dev" --label "team:infra" +``` + +### 4. Launch Squad in each Codespace + +Each Codespace runs `squad` normally. The SubSquad context is detected automatically: + +```bash +# In Codespace 1 (SQUAD_TEAM=ui-team) +squad +# → Ralph only triages issues labeled "team:ui" +# → Agents only modify files in src/client, src/components + +# In Codespace 2 (SQUAD_TEAM=backend-team) +squad +# → Ralph only triages issues labeled "team:backend" +# → Agents only modify files in src/server, src/shared +``` + +### 5. Monitor across SubSquads + +Use the CLI from any Codespace to see all SubSquads: + +```bash +squad subsquads status +``` + + + + +## What Worked + +- **Clear separation**: Each SubSquad had well-defined boundaries, minimizing merge conflicts +- **Parallel velocity**: 3x throughput vs. single-squad mode for independent work +- **Label-based routing**: Simple, uses existing GitHub infrastructure + +## What Didn't Work (Yet) + +- **Cross-SubSquad dependencies**: When the UI team needed a backend API change, manual coordination was required +- **Shared files**: `package.json`, `tsconfig.json`, and other root files caused occasional conflicts +- **No meta-coordinator**: No automated way to coordinate across SubSquads (future work) + +## Lessons Learned + +1. **Keep SubSquads independent** — design folder boundaries to minimize shared files +2. **Use branch-per-issue** — direct commits across SubSquads cause merge hell +3. **Label everything** — unlabeled issues get lost between SubSquads +4. **Start with 2 SubSquads** — add more once the team finds its rhythm diff --git a/docs/scenarios/multiple-squads.md b/docs/src/content/docs/scenarios/multiple-squads.md similarity index 100% rename from docs/scenarios/multiple-squads.md rename to docs/src/content/docs/scenarios/multiple-squads.md diff --git a/docs/scenarios/new-project.md b/docs/src/content/docs/scenarios/new-project.md similarity index 100% rename from docs/scenarios/new-project.md rename to docs/src/content/docs/scenarios/new-project.md diff --git a/docs/scenarios/open-source.md b/docs/src/content/docs/scenarios/open-source.md similarity index 100% rename from docs/scenarios/open-source.md rename to docs/src/content/docs/scenarios/open-source.md diff --git a/docs/scenarios/private-repos.md b/docs/src/content/docs/scenarios/private-repos.md similarity index 100% rename from docs/scenarios/private-repos.md rename to docs/src/content/docs/scenarios/private-repos.md diff --git a/docs/scenarios/release-process.md b/docs/src/content/docs/scenarios/release-process.md similarity index 100% rename from docs/scenarios/release-process.md rename to docs/src/content/docs/scenarios/release-process.md diff --git a/docs/scenarios/scaling-workstreams.md b/docs/src/content/docs/scenarios/scaling-workstreams.md similarity index 96% rename from docs/scenarios/scaling-workstreams.md rename to docs/src/content/docs/scenarios/scaling-workstreams.md index ef2e27a22..481c7cf42 100644 --- a/docs/scenarios/scaling-workstreams.md +++ b/docs/src/content/docs/scenarios/scaling-workstreams.md @@ -1,168 +1,168 @@ -# Scaling with SubSquads - -> Partition your repo's work across multiple Squad instances for horizontal scaling. - -## The Problem - -A single Squad instance handles all issues in a repo. For large projects, this creates bottlenecks: -- Too many issues overwhelm a single team -- Agents step on each other's toes in shared code -- No workflow enforcement (agents commit directly to main) -- No way to monitor multiple teams centrally - -## The Solution: SubSquads - -SubSquads partition a repo's issues into labeled subsets. Each Codespace (or machine) runs one SubSquad, scoped to its slice of work. - -``` -┌─────────────────────────────────────────────────┐ -│ Repository: acme/starship │ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ -│ │ Codespace 1 │ │ Codespace 2 │ │ Codespace 3│ │ -│ │ team:bridge │ │ team:engine │ │ team:ops │ │ -│ │ Picard,Riker│ │ Geordi,Worf │ │ Troi,Crusher│ │ -│ │ UI + API │ │ Core engine │ │ Infra + CI │ │ -│ └─────────────┘ └─────────────┘ └───────────┘ │ -│ │ -│ Each Squad instance only picks up issues │ -│ matching its SubSquad label. │ -└─────────────────────────────────────────────────┘ -``` - -## Quick Start - -### 1. Define SubSquads - -Create `.squad/streams.json`: - -```json -{ - "defaultWorkflow": "branch-per-issue", - "workstreams": [ - { - "name": "bridge", - "labelFilter": "team:bridge", - "folderScope": ["src/api", "src/ui"], - "description": "Bridge crew — API and UI" - }, - { - "name": "engine", - "labelFilter": "team:engine", - "folderScope": ["src/core", "src/engine"], - "description": "Engineering — core systems" - }, - { - "name": "ops", - "labelFilter": "team:ops", - "folderScope": ["infra/", "scripts/", ".github/"], - "description": "Operations — CI/CD and infra" - } - ] -} -``` - -### 2. Label your issues - -Each issue gets a `team:*` label matching a SubSquad. Ralph will only pick up issues matching the active SubSquad's label. - -### 3. Activate a SubSquad - -**Option A — Environment variable (Codespaces):** -Set `SQUAD_TEAM=bridge` in the Codespace's environment. Squad auto-detects it on session start. - -**Option B — CLI activation (local):** -```bash -squad subsquads activate bridge -``` -This writes a `.squad-workstream` file (gitignored — local to your machine). - -**Option C — Single SubSquad auto-select:** -If `streams.json` defines only one SubSquad, it's auto-selected. - -### 4. Run Squad normally - -```bash -squad start -# or: "Ralph, go" in the session -``` - -Ralph will only scan for issues with the `team:bridge` label. Agents will only pick up matching work. - -## CLI Commands - -```bash -# List configured SubSquads -squad subsquads list - -# Show activity per SubSquad (branches, PRs) -squad subsquads status - -# Activate a SubSquad for this machine -squad subsquads activate engine - -# Deprecated aliases (still work) -squad workstreams list -squad streams list -``` - -> **Note:** `squad workstreams` and `squad streams` are deprecated aliases for `squad subsquads`. - -## Key Design Decisions - -### folderScope is Advisory - -`folderScope` tells agents which directories to focus on — but it's not a hard lock. Agents can modify shared packages (like `src/shared/`) when needed, and will call out when working outside their scope. - -### Workflow Enforcement - -Each SubSquad specifies a `workflow` (default: `branch-per-issue`). When active, agents: -- Create a branch for every issue (`squad/{issue-number}-{slug}`) -- Open a PR when work is ready -- Never commit directly to main - -### Single-Machine Multi-SubSquad - -You don't need multiple Codespaces to test. Use `squad subsquads activate` to switch between SubSquads sequentially on a single machine. - -## Resolution Chain - -Squad resolves the active SubSquad in this order: - -1. `SQUAD_TEAM` environment variable -2. `.squad-workstream` file (written by `squad subsquads activate`) -3. Auto-select if exactly one SubSquad is defined -4. No SubSquad → single-squad mode (backward compatible) - -## Monitoring - -Use `squad subsquads status` to see all SubSquads' activity: - -``` -Configured SubSquads - - Default workflow: branch-per-issue - - ● active bridge - Label: team:bridge - Workflow: branch-per-issue - Folders: src/api, src/ui - - ○ engine - Label: team:engine - Workflow: branch-per-issue - Folders: src/core, src/engine - - ○ ops - Label: team:ops - Workflow: branch-per-issue - Folders: infra/, scripts/, .github/ - - Active SubSquad resolved via: env -``` - -## See Also - -- [Multi-Codespace Setup](multi-codespace.md) — Walkthrough of the Tetris experiment -- [SubSquads PRD](../specs/streams-prd.md) — Full specification -- [SubSquads Feature Guide](../features/streams.md) — API reference +# Scaling with SubSquads + +> Partition your repo's work across multiple Squad instances for horizontal scaling. + +## The Problem + +A single Squad instance handles all issues in a repo. For large projects, this creates bottlenecks: +- Too many issues overwhelm a single team +- Agents step on each other's toes in shared code +- No workflow enforcement (agents commit directly to main) +- No way to monitor multiple teams centrally + +## The Solution: SubSquads + +SubSquads partition a repo's issues into labeled subsets. Each Codespace (or machine) runs one SubSquad, scoped to its slice of work. + +``` +┌─────────────────────────────────────────────────┐ +│ Repository: acme/starship │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ +│ │ Codespace 1 │ │ Codespace 2 │ │ Codespace 3│ │ +│ │ team:bridge │ │ team:engine │ │ team:ops │ │ +│ │ Picard,Riker│ │ Geordi,Worf │ │ Troi,Crusher│ │ +│ │ UI + API │ │ Core engine │ │ Infra + CI │ │ +│ └─────────────┘ └─────────────┘ └───────────┘ │ +│ │ +│ Each Squad instance only picks up issues │ +│ matching its SubSquad label. │ +└─────────────────────────────────────────────────┘ +``` + +## Quick Start + +### 1. Define SubSquads + +Create `.squad/streams.json`: + +```json +{ + "defaultWorkflow": "branch-per-issue", + "workstreams": [ + { + "name": "bridge", + "labelFilter": "team:bridge", + "folderScope": ["src/api", "src/ui"], + "description": "Bridge crew — API and UI" + }, + { + "name": "engine", + "labelFilter": "team:engine", + "folderScope": ["src/core", "src/engine"], + "description": "Engineering — core systems" + }, + { + "name": "ops", + "labelFilter": "team:ops", + "folderScope": ["infra/", "scripts/", ".github/"], + "description": "Operations — CI/CD and infra" + } + ] +} +``` + +### 2. Label your issues + +Each issue gets a `team:*` label matching a SubSquad. Ralph will only pick up issues matching the active SubSquad's label. + +### 3. Activate a SubSquad + +**Option A — Environment variable (Codespaces):** +Set `SQUAD_TEAM=bridge` in the Codespace's environment. Squad auto-detects it on session start. + +**Option B — CLI activation (local):** +```bash +squad subsquads activate bridge +``` +This writes a `.squad-workstream` file (gitignored — local to your machine). + +**Option C — Single SubSquad auto-select:** +If `streams.json` defines only one SubSquad, it's auto-selected. + +### 4. Run Squad normally + +```bash +squad start +# or: "Ralph, go" in the session +``` + +Ralph will only scan for issues with the `team:bridge` label. Agents will only pick up matching work. + +## CLI Commands + +```bash +# List configured SubSquads +squad subsquads list + +# Show activity per SubSquad (branches, PRs) +squad subsquads status + +# Activate a SubSquad for this machine +squad subsquads activate engine + +# Deprecated aliases (still work) +squad workstreams list +squad streams list +``` + +> **Note:** `squad workstreams` and `squad streams` are deprecated aliases for `squad subsquads`. + +## Key Design Decisions + +### folderScope is Advisory + +`folderScope` tells agents which directories to focus on — but it's not a hard lock. Agents can modify shared packages (like `src/shared/`) when needed, and will call out when working outside their scope. + +### Workflow Enforcement + +Each SubSquad specifies a `workflow` (default: `branch-per-issue`). When active, agents: +- Create a branch for every issue (`squad/{issue-number}-{slug}`) +- Open a PR when work is ready +- Never commit directly to main + +### Single-Machine Multi-SubSquad + +You don't need multiple Codespaces to test. Use `squad subsquads activate` to switch between SubSquads sequentially on a single machine. + +## Resolution Chain + +Squad resolves the active SubSquad in this order: + +1. `SQUAD_TEAM` environment variable +2. `.squad-workstream` file (written by `squad subsquads activate`) +3. Auto-select if exactly one SubSquad is defined +4. No SubSquad → single-squad mode (backward compatible) + +## Monitoring + +Use `squad subsquads status` to see all SubSquads' activity: + +``` +Configured SubSquads + + Default workflow: branch-per-issue + + ● active bridge + Label: team:bridge + Workflow: branch-per-issue + Folders: src/api, src/ui + + ○ engine + Label: team:engine + Workflow: branch-per-issue + Folders: src/core, src/engine + + ○ ops + Label: team:ops + Workflow: branch-per-issue + Folders: infra/, scripts/, .github/ + + Active SubSquad resolved via: env +``` + +## See Also + +- [Multi-Codespace Setup](multi-codespace.md) — Walkthrough of the Tetris experiment +- [SubSquads PRD](../specs/streams-prd.md) — Full specification +- [SubSquads Feature Guide](../features/streams.md) — API reference diff --git a/docs/scenarios/solo-dev.md b/docs/src/content/docs/scenarios/solo-dev.md similarity index 100% rename from docs/scenarios/solo-dev.md rename to docs/src/content/docs/scenarios/solo-dev.md diff --git a/docs/scenarios/switching-models.md b/docs/src/content/docs/scenarios/switching-models.md similarity index 100% rename from docs/scenarios/switching-models.md rename to docs/src/content/docs/scenarios/switching-models.md diff --git a/docs/scenarios/team-of-humans.md b/docs/src/content/docs/scenarios/team-of-humans.md similarity index 100% rename from docs/scenarios/team-of-humans.md rename to docs/src/content/docs/scenarios/team-of-humans.md diff --git a/docs/scenarios/team-portability.md b/docs/src/content/docs/scenarios/team-portability.md similarity index 100% rename from docs/scenarios/team-portability.md rename to docs/src/content/docs/scenarios/team-portability.md diff --git a/docs/scenarios/team-state-storage.md b/docs/src/content/docs/scenarios/team-state-storage.md similarity index 100% rename from docs/scenarios/team-state-storage.md rename to docs/src/content/docs/scenarios/team-state-storage.md diff --git a/docs/scenarios/troubleshooting.md b/docs/src/content/docs/scenarios/troubleshooting.md similarity index 100% rename from docs/scenarios/troubleshooting.md rename to docs/src/content/docs/scenarios/troubleshooting.md diff --git a/docs/scenarios/upgrading.md b/docs/src/content/docs/scenarios/upgrading.md similarity index 100% rename from docs/scenarios/upgrading.md rename to docs/src/content/docs/scenarios/upgrading.md diff --git a/docs/sdk-first-mode.md b/docs/src/content/docs/sdk-first-mode.md similarity index 100% rename from docs/sdk-first-mode.md rename to docs/src/content/docs/sdk-first-mode.md diff --git a/docs/tips-and-tricks.md b/docs/src/content/docs/tips-and-tricks.md similarity index 100% rename from docs/tips-and-tricks.md rename to docs/src/content/docs/tips-and-tricks.md diff --git a/docs/tour-first-session.md b/docs/src/content/docs/tour-first-session.md similarity index 100% rename from docs/tour-first-session.md rename to docs/src/content/docs/tour-first-session.md diff --git a/docs/tour-github-issues.md b/docs/src/content/docs/tour-github-issues.md similarity index 100% rename from docs/tour-github-issues.md rename to docs/src/content/docs/tour-github-issues.md diff --git a/docs/tour-gitlab-issues.md b/docs/src/content/docs/tour-gitlab-issues.md similarity index 100% rename from docs/tour-gitlab-issues.md rename to docs/src/content/docs/tour-gitlab-issues.md diff --git a/docs/whatsnew.md b/docs/src/content/docs/whatsnew.md similarity index 100% rename from docs/whatsnew.md rename to docs/src/content/docs/whatsnew.md diff --git a/docs/src/layouts/BaseLayout.astro b/docs/src/layouts/BaseLayout.astro new file mode 100644 index 000000000..db21b80c0 --- /dev/null +++ b/docs/src/layouts/BaseLayout.astro @@ -0,0 +1,33 @@ +--- +interface Props { + title: string; + description?: string; +} + +const { title, description = 'Squad — Your AI Development Team. Describe what you\'re building. Get a team of specialists that live in your repo.' } = Astro.props; +const base = import.meta.env.BASE_URL; +--- + + + + + + + + + + {title} — Squad Docs + + + + + + + diff --git a/docs/src/layouts/DocsLayout.astro b/docs/src/layouts/DocsLayout.astro new file mode 100644 index 000000000..979bdd583 --- /dev/null +++ b/docs/src/layouts/DocsLayout.astro @@ -0,0 +1,29 @@ +--- +import BaseLayout from './BaseLayout.astro'; +import Header from '../components/Header.astro'; +import Sidebar from '../components/Sidebar.astro'; +import Footer from '../components/Footer.astro'; + +interface Props { + title: string; + description?: string; + currentSlug?: string; +} + +const { title, description, currentSlug } = Astro.props; +--- + + +
+
+ +
+
+
+ +
+
+
+
+
+ diff --git a/docs/src/navigation.ts b/docs/src/navigation.ts new file mode 100644 index 000000000..f8dece583 --- /dev/null +++ b/docs/src/navigation.ts @@ -0,0 +1,134 @@ +export interface NavItem { + title: string; + slug: string; +} + +export interface NavSection { + title: string; + dir: string; + items: NavItem[]; +} + +export const NAV_SECTIONS: NavSection[] = [ + { + title: 'Get Started', + dir: 'get-started', + items: [ + { title: 'Installation', slug: 'get-started/installation' }, + { title: 'Your First Session', slug: 'get-started/first-session' }, + { title: 'Migration Guide', slug: 'get-started/migration' }, + ], + }, + { + title: 'Guide', + dir: 'guide', + items: [ + { title: 'Tips & Tricks', slug: 'guide/tips-and-tricks' }, + { title: 'Sample Prompts', slug: 'guide/sample-prompts' }, + { title: 'Personal Squad', slug: 'guide/personal-squad' }, + { title: 'Contributing', slug: 'guide/contributing' }, + { title: 'Contributors', slug: 'guide/contributors' }, + ], + }, + { + title: 'Features', + dir: 'features', + items: [ + { title: 'Team Setup', slug: 'features/team-setup' }, + { title: 'Work Routing', slug: 'features/routing' }, + { title: 'Model Selection', slug: 'features/model-selection' }, + { title: 'Response Modes', slug: 'features/response-modes' }, + { title: 'Parallel Execution', slug: 'features/parallel-execution' }, + { title: 'Memory', slug: 'features/memory' }, + { title: 'Skills', slug: 'features/skills' }, + { title: 'Directives', slug: 'features/directives' }, + { title: 'Ceremonies', slug: 'features/ceremonies' }, + { title: 'Reviewer Protocol', slug: 'features/reviewer-protocol' }, + { title: 'GitHub Issues', slug: 'features/github-issues' }, + { title: 'GitLab Issues', slug: 'features/gitlab-issues' }, + { title: 'Labels & Triage', slug: 'features/labels' }, + { title: 'PRD Mode', slug: 'features/prd-mode' }, + { title: 'Project Boards', slug: 'features/project-boards' }, + { title: 'Ralph — Work Monitor', slug: 'features/ralph' }, + { title: '@copilot Coding Agent', slug: 'features/copilot-coding-agent' }, + { title: 'Human Team Members', slug: 'features/human-team-members' }, + { title: 'Consult Mode', slug: 'features/consult-mode' }, + { title: 'Remote Control', slug: 'features/remote-control' }, + { title: 'VS Code', slug: 'features/vscode' }, + { title: 'Git Worktrees', slug: 'features/worktrees' }, + { title: 'Export & Import', slug: 'features/export-import' }, + { title: 'Upstream Inheritance', slug: 'features/upstream-inheritance' }, + { title: 'Marketplace', slug: 'features/marketplace' }, + { title: 'Plugins', slug: 'features/plugins' }, + { title: 'MCP', slug: 'features/mcp' }, + { title: 'Notifications', slug: 'features/notifications' }, + { title: 'Enterprise Platforms', slug: 'features/enterprise-platforms' }, + { title: 'Squad RC', slug: 'features/squad-rc' }, + { title: 'Streams', slug: 'features/streams' }, + ], + }, + { + title: 'Reference', + dir: 'reference', + items: [ + { title: 'CLI', slug: 'reference/cli' }, + { title: 'SDK', slug: 'reference/sdk' }, + { title: 'Config', slug: 'reference/config' }, + ], + }, + { + title: 'Scenarios', + dir: 'scenarios', + items: [ + { title: 'Existing Repo', slug: 'scenarios/existing-repo' }, + { title: 'New Project', slug: 'scenarios/new-project' }, + { title: 'Solo Developer', slug: 'scenarios/solo-dev' }, + { title: 'Issue-Driven Dev', slug: 'scenarios/issue-driven-dev' }, + { title: 'Monorepo', slug: 'scenarios/monorepo' }, + { title: 'CI/CD Integration', slug: 'scenarios/ci-cd-integration' }, + { title: 'Team of Humans', slug: 'scenarios/team-of-humans' }, + { title: 'Large Codebase', slug: 'scenarios/large-codebase' }, + { title: 'Open Source', slug: 'scenarios/open-source' }, + { title: 'Multiple Squads', slug: 'scenarios/multiple-squads' }, + { title: 'Keep My Squad', slug: 'scenarios/keep-my-squad' }, + { title: 'Mid-Project', slug: 'scenarios/mid-project' }, + { title: 'Upgrading', slug: 'scenarios/upgrading' }, + { title: 'Multi-Codespace', slug: 'scenarios/multi-codespace' }, + { title: 'Private Repos', slug: 'scenarios/private-repos' }, + { title: 'Team Portability', slug: 'scenarios/team-portability' }, + { title: 'Team State Storage', slug: 'scenarios/team-state-storage' }, + { title: 'Switching Models', slug: 'scenarios/switching-models' }, + { title: 'Release Process', slug: 'scenarios/release-process' }, + { title: 'Scaling Workstreams', slug: 'scenarios/scaling-workstreams' }, + { title: 'Client Compatibility', slug: 'scenarios/client-compatibility' }, + { title: 'Disaster Recovery', slug: 'scenarios/disaster-recovery' }, + { title: 'Troubleshooting', slug: 'scenarios/troubleshooting' }, + { title: 'Aspire Dashboard', slug: 'scenarios/aspire-dashboard' }, + ], + }, + { + title: 'Concepts', + dir: 'concepts', + items: [ + { title: 'Your Team', slug: 'concepts/your-team' }, + { title: 'Memory & Knowledge', slug: 'concepts/memory-and-knowledge' }, + { title: 'Parallel Work', slug: 'concepts/parallel-work' }, + { title: 'GitHub Workflow', slug: 'concepts/github-workflow' }, + { title: 'Portability', slug: 'concepts/portability' }, + ], + }, + { + title: 'Cookbook', + dir: 'cookbook', + items: [ + { title: 'Recipes', slug: 'cookbook/recipes' }, + ], + }, +]; + +export const STANDALONE_PAGES = [ + { title: "What's New", slug: 'whatsnew' }, + { title: 'SDK-First Mode', slug: 'sdk-first-mode' }, + { title: 'Community', slug: 'community' }, + { title: 'Insider Program', slug: 'insider-program' }, +]; diff --git a/docs/src/pages/404.astro b/docs/src/pages/404.astro new file mode 100644 index 000000000..3869ac986 --- /dev/null +++ b/docs/src/pages/404.astro @@ -0,0 +1,21 @@ +--- +import BaseLayout from '../layouts/BaseLayout.astro'; +import Header from '../components/Header.astro'; +import Footer from '../components/Footer.astro'; + +const base = import.meta.env.BASE_URL; +--- + + +
+
+

404

+

Page not found

+

The page you're looking for doesn't exist or has been moved.

+ +
+