diff --git a/.ai-team/agents/baer/history.md b/.ai-team/agents/baer/history.md deleted file mode 100644 index d30ef0118..000000000 --- a/.ai-team/agents/baer/history.md +++ /dev/null @@ -1,54 +0,0 @@ -# Baer — History - -## Project Context - -- **Owner:** bradygaster -- **Stack:** Node.js, GitHub Copilot CLI, multi-agent orchestration -- **Description:** Squad democratizes multi-agent development — one command gives you a team that evolves with your product. Built to bring personality and real multi-agent patterns to the GitHub Copilot ecosystem. -- **Created:** 2026-02-07 - -## Day-1 Context - -- Hired during v0.4.2 release cycle after Brady caught an email privacy issue -- The team was storing `git config user.email` in committed `.ai-team/` files — PII leak -- Immediate fix shipped: squad.agent.md no longer reads email, 9 files scrubbed -- v0.5.0 migration tool (#108) needs to scrub email from customer repos too -- Key decision already made: "Never store user email addresses in committed files" -- v0.5.0 is a major rename (.ai-team/ → .squad/) — security review needed for migration -- v0.5.0 also adds identity layer (wisdom.md, now.md) — review data sensitivity - -## Learnings - -- Squad files (.ai-team/) are committed to git and pushed to remotes — anything written there is public -- Guard workflow blocks .ai-team/ from main/preview/insider branches, but it's still in git history on dev/feature branches -- GitHub Actions bot email (github-actions[bot]@users.noreply.github.com) is standard and not PII -- Plugin marketplace sources are stored in .ai-team/plugins/marketplaces.json — external repo references, not sensitive -- MCP server configs can contain API keys via env vars (${TRELLO_API_KEY}) — these should never be committed -- Template files (`templates/history.md`, `templates/roster.md`, `.ai-team-templates/history.md`) still contain `{user email}` placeholder — contradicts the email prohibition in squad.agent.md -- `git config user.name` is stored in team.md, session logs, orchestration logs, and passed to every spawn prompt — low risk since it's already in git commits, but constitutes PII under GDPR -- `squad export` serializes all agent histories to JSON — may contain PII (names, internal URLs). Warning exists but could be stronger -- Plugin marketplace has no content verification — SKILL.md files from arbitrary repos are loaded directly into agent context windows (prompt injection vector) -- Issue and PR bodies are injected into agent prompts without sanitization — prompt injection risk via GitHub issues -- decisions.md is append-only with no archival — grows unbounded (~300KB in source repo), may accumulate sensitive business context -- GitHub custom agents allow up to 30,000 characters in `.agent.md` files — squad.agent.md may exceed this if enforced -- MCP data flow: user request → coordinator → agent → MCP server → third-party API. Users may not realize project data flows to Trello/Notion/Azure when MCP tools are configured -- Committed MCP config files (`.copilot/mcp-config.json`, `.vscode/mcp.json`) use `${VAR}` references — correct pattern, but no guardrail prevents hardcoded secrets -- Security audit v1 findings written to `.ai-team/decisions/inbox/baer-security-audit-v1.md` — 12 findings across PII, compliance, third-party data, git history, and threat model -- Issue #108: Built email scrubber for migration flow — scans team.md, history.md, decisions.md, logs for `name (email)` and bare emails, replaces with `[email scrubbed]` -- Email scrubbing integrated as v0.5.0 migration — runs automatically during `squad upgrade` and reports files cleaned -- `squad scrub-emails` command added for manual scrubbing — defaults to .ai-team/ directory -- Email regex: `/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g` — careful to preserve emails in URLs, code blocks, example.com contexts -- Git history caveat documented — scrubber only touches working tree, git history requires `git-filter-repo` for complete removal -- Fixed unfinished squadInfo/detectSquadDir implementation — dev branch had broken references causing 43 test failures -- PRD 3 (Hooks & Policy Enforcement) written at `.ai-team/docs/prds/03-hooks-policy-enforcement.md` — comprehensive governance-as-code transformation plan -- Inventoried 18 hook-enforceable policies (P1–P18) and 17 prompt-only behavioral policies (B1–B17) from squad.agent.md -- SDK hook system has 6 hooks (preToolUse, postToolUse, userPromptSubmitted, sessionStart, sessionEnd, errorOccurred) + 2 handlers (onPermissionRequest, onUserInputRequest) -- `onPreToolUse` with `permissionDecision: "deny"` is the primary enforcement primitive — hard blocks the tool call, model receives denial reason as context -- Policy composition uses middleware pipeline pattern — multiple policies per hook, first deny wins, each independently testable -- Hybrid approach required: some policies need both prompt guidance (model understands why) and hook enforcement (system guarantees it) -- Prompt size reduction estimated at ~2.5–6KB (~800–1,800 tokens) from always-loaded governance section — percentage is against governance portion, not full prompt -- Key open question: does `onPreToolUse` fire for ALL built-in tools? Must verify in Phase 1 POC. If not, `onPermissionRequest` is the fallback layer -- PII scrubbing in `onPostToolUse` is defense-in-depth — catches secrets in tool outputs that prompt-level rules cannot prevent -- Lockout registry needs persistent storage (`.squad/lockout.json`) to survive session restarts — Scribe as sole writer (single-writer pattern) -📌 Team update (2026-02-20): SDK replatform PRD 3 (Hooks & Policy Enforcement) documented. 18 hook-enforceable policies (P1–P18), 17 prompt-only policies (B1–B17), 5 hybrid (H1–H5). Primary enforcement: onPreToolUse with permissionDecision: "deny". Middleware pipeline composition. PII scrubbing in onPostToolUse. Policy config in .squad/config/policies.json. Brady pending: denial visibility, scrubbing scope, lockout persistence, force-with-lease default. — decided by Baer with Keaton, Fenster, Verbal, Kujan -- **M1-5 (#119) + M1-6 (#120) complete:** Implemented HookPipeline with 4 policy enforcers + ReviewerLockoutHook. File-write guard blocks unauthorized paths (glob matching). Shell command restrictor blocks dangerous commands (rm -rf, git push --force, git rebase, git reset --hard). PII scrubber strips emails from tool output (regex-based, recursive object traversal). ask_user rate limiter prevents excessive prompts per session. Reviewer lockout maintains Map> registry — blocks locked-out agents from editing artifacts. All policies individually toggleable via PolicyConfig. Comprehensive test suite (30 tests) covers happy paths, edge cases, glob matching, Windows paths, pipeline ordering, empty pipelines. Glob matcher bug fixed (escape `.` before wildcard substitution). Build + tests passing. Critical security milestone: PII scrubbing now deterministic, not prompt-dependent. diff --git a/.ai-team/agents/edie/charter.md b/.ai-team/agents/edie/charter.md deleted file mode 100644 index db35c187e..000000000 --- a/.ai-team/agents/edie/charter.md +++ /dev/null @@ -1,43 +0,0 @@ -# Edie — TypeScript Engineer - -> Types are contracts. If it compiles, it works. If it doesn't compile, it shouldn't. - -## Identity -- **Name:** Edie -- **Role:** TypeScript Engineer -- **Expertise:** TypeScript generics, ESM module systems, strict mode, type-safe patterns, build tooling (esbuild, tsc), declaration files, tsconfig optimization -- **Style:** Precise, type-obsessed, catches problems at compile time not runtime. Makes APIs impossible to misuse. - -## What I Own -- TypeScript architecture — module boundaries, export surfaces, generic patterns -- Build pipeline — tsc, esbuild, bundling configuration, source maps -- Type safety — strict mode compliance, no `any` escape hatches, proper narrowing -- API design — type-safe interfaces that guide consumers toward correct usage -- ESM/CJS interop — module resolution, package.json exports field, dual-package patterns - -## How I Work -- Start with the types: define interfaces before implementations -- Strict mode always — `strict: true`, `noUncheckedIndexedAccess: true`, no compromises -- Generics over unions when the pattern recurs -- Build must be reproducible — same inputs, same outputs, every time -- Declaration files are part of the public API — they get reviewed like code - -## Boundaries -**I handle:** TypeScript architecture, build pipeline, type-safe API design, module systems -**I don't handle:** Product direction (that's Keaton), runtime performance tuning (that's Fortier), prompt design (that's Verbal) -**When I'm unsure:** If it's an architectural decision, Keaton decides. If it's runtime behavior, Fortier knows. -**If I review others' work:** On rejection, I may require a different agent to revise (not the original author) or request a new specialist be spawned. The Coordinator enforces this. - -## Model -- **Preferred:** claude-sonnet-4.5 -- **Rationale:** Writes code — quality and type-safety accuracy first. -- **Fallback:** Standard chain - -## Collaboration -Before starting work, run `git rev-parse --show-toplevel` to find the repo root, or use the `TEAM ROOT` provided in the spawn prompt. All `.ai-team/` paths must be resolved relative to this root — do not assume CWD is the repo root (you may be in a worktree or subdirectory). -Before starting work, read `.ai-team/decisions.md` for team decisions that affect me. -After making a decision others should know, write it to `.ai-team/decisions/inbox/edie-{brief-slug}.md` — the Scribe will merge it. -If I need another team member's input, say so — the coordinator will bring them in. - -## Voice -Opinionated about type safety. Will push back if someone introduces `any`, loose types, or runtime checks where compile-time guarantees are possible. Thinks the best TypeScript code reads like documentation — types tell the story. diff --git a/.ai-team/agents/edie/history.md b/.ai-team/agents/edie/history.md deleted file mode 100644 index 782e56ca1..000000000 --- a/.ai-team/agents/edie/history.md +++ /dev/null @@ -1,72 +0,0 @@ -# Edie — TypeScript Engineer - -## Core Context -- **Project:** Squad — AI agent teams for GitHub Copilot -- **Owner:** Brady (bradygaster) -- **Stack:** TypeScript, Node.js ≥20, ESM, @github/copilot-sdk -- **Focus:** Replatforming Squad from prompt-only architecture to Copilot SDK runtime -- **New repo:** C:\src\squad-sdk (bradygaster/squad-pr on GitHub) -- **Language decision:** TypeScript locked in (unanimous team recommendation) -- **Key PRDs:** 1 (SDK Runtime), 2 (Tools), 3 (Hooks), 4 (Agent Lifecycle), 5 (Coordinator) -- **Key directives:** Single .squad/ directory, global install, agent repositories, zero-config - -## Learnings -- Joined 2026-02-20 as part of the replatform recruitment wave -- Squad's current implementation is in index.js (vanilla Node.js) — being rebuilt in TypeScript -- Copilot SDK is at C:\src\copilot-sdk — TypeScript, ESM, Node.js ≥20 -- squad-sdk repo already has typed stubs in src/ — client/, tools/, hooks/, agents/, coordinator/, casting/, ralph/ -- 14 PRDs define the full replatform plan, stored at C:\src\squad\.ai-team\docs\prds\ - -### SDK Type System Deep Dive (2026-02-20) -- SDK has `strict: true`, exactly one `any` (in `SessionConfig.tools` — correctly annotated), zero `as unknown`/`@ts-ignore` -- `SessionEvent` is a ~700-line discriminated union (35+ event types) generated from JSON schema — the star type -- `SessionEventPayload` uses `Extract` for narrowed typed event handlers -- `defineTool()` uses `ZodSchema` phantom type (`_output: T`) for generic inference from Zod schemas to handlers -- Generated RPC layer (`createServerRpc`, `createSessionRpc`) uses `Omit` for session-scoped method signatures -- SDK uses `vscode-jsonrpc` which returns untyped responses — all `sendRequest()` calls require `as` casts in client.ts -- SDK tsconfig lacks `noUncheckedIndexedAccess` and uses legacy `moduleResolution: "node"` (esbuild does actual bundling) -- Hook system has per-hook-type Input/Output interfaces — fully typed, no generic `Function` types -- `MCPServerConfig` is a discriminated union: `MCPLocalServerConfig | MCPRemoteServerConfig` -- SDK depends on Zod v4.x (`^4.3.6`) — we need to match this version exactly -- No branded/nominal types for IDs (sessionId, toolCallId, messageId all plain `string`) -- No custom error hierarchy — all errors are plain `Error` with string messages - -### Squad Stub Alignment Issues Found (2026-02-20) -- Our `CustomAgentConfig.displayName`/`description` are required but SDK has them optional -- Our `McpServerConfig` is `{ command, args?, env? }` — missing remote server support and required `tools` field -- `ToolRegistry` uses `Map` — should be `Map>` -- `SquadEvent.payload` is `unknown` — should be a discriminated union per event type -- Hook types add `agentName` not in SDK — need adapter layer to bridge -- `@types/node` version mismatch: ours `^22`, SDK has `^25` -- Missing `zod` dependency in squad-sdk package.json (needed for PRD 2) -- Missing `noUncheckedIndexedAccess: true` in our tsconfig - -## Recent Updates -### Template Migration for PRD 16 (2026-02-20) -- Copied 34 template files from beta repo (C:\src\squad\templates\) to squad-sdk repo -- Includes squad.agent.md coordinator prompt, workflows, casting data, template files -- Created `src/cli/core/templates.ts` with TypeScript manifest -- Manifest categorizes files: squad-owned (overwriteOnUpgrade: true) vs user-owned (false) -- Squad-owned: coordinator, workflows, casting system, template files -- User-owned: ceremonies.md, routing.md, identity/, agent-specific files -- Exported via cli/index.ts barrel, build verified -- PR #172 created: https://github.com/bradygaster/squad-pr/pull/172 - -### PRD 17: Upgrade Command (2026-02-21) -- Implemented full upgrade command from beta CLI (1,500+ LOC port) -- Created `src/cli/core/upgrade.ts` — main upgrade logic with version comparison -- Created `src/cli/core/migrations.ts` — version-based additive migration runner -- Created `src/cli/core/email-scrub.ts` — PII cleanup utility (scrubs email addresses) -- Created `src/cli/core/migrate-directory.ts` — .ai-team/ → .squad/ migration -- Zero-dep implementation using Node.js stdlib only (fs, path) -- Squad-owned file overwrite (uses TEMPLATE_MANIFEST.overwriteOnUpgrade flags) -- Project-type detection (npm/go/python/java/dotnet/unknown) -- Workflow generation (project-type-aware stubs for non-npm projects) -- Version stamping on squad.agent.md (HTML comment + Identity section) -- Migration registry: v0.2.0 (skills/), v0.4.0 (plugins/), v0.5.0 (email scrub) -- --migrate-directory flag: renames .ai-team/ → .squad/, updates .gitattributes/.gitignore -- Wired into CLI router (src/index.ts) — async main() function -- Fixed type conflicts between cli/core/upgrade.ts and cli/upgrade.ts (SDK stub) -- Fixed stampVersion export conflict (build/versioning.ts vs cli/core/version.ts) -- Build passes, tests pass (43/43 in cli.test.ts, 2 unrelated failures elsewhere) -- PR #174 created: https://github.com/bradygaster/squad-pr/pull/174 diff --git a/.ai-team/agents/fenster/history.md b/.ai-team/agents/fenster/history.md deleted file mode 100644 index e2efdc14e..000000000 --- a/.ai-team/agents/fenster/history.md +++ /dev/null @@ -1,302 +0,0 @@ -# Project Context - -- **Owner:** bradygaster -- **Project:** Squad — AI agent teams that grow with your code. Democratizing multi-agent development on GitHub Copilot. Mission: beat the industry to what customers need next. -- **Stack:** Node.js, GitHub Copilot CLI, multi-agent orchestration -- **Created:** 2026-02-07 - -## Core Context - -_Summarized from initial architecture review (2026-02-07). Full entries in `history-archive.md`._ - -- **Squad is a markdown-as-runtime system** — the entire orchestration is a 32KB `.github/agents/squad.agent.md` file interpreted by the LLM. `index.js` is a minimal installer (~65 lines initially) that copies the coordinator manifest and templates. -- **File system is the IPC layer** — agents write decisions to `.ai-team/decisions/inbox/`, Scribe merges to canonical `decisions.md`. This drop-box pattern eliminates write conflicts during parallel spawns. -- **File ownership model is foundational** — Squad-owned files (squad.agent.md, templates) are safe to overwrite on upgrade. User-owned files (.ai-team/) are never touched. This classification drives the entire forwardability strategy. -- **Upgrade architecture uses version-keyed idempotent migrations** — version detection via frontmatter parsing, backup before overwrite, `process.argv[2]` subcommand routing with no external dependencies. -- **Windows path safety is non-negotiable** — all file operations use `path.join()`, no hardcoded separators, no symlinks, pure `fs` operations only. -- **Key file paths**: `squad.agent.md` (coordinator), `index.js` (installer), `.ai-team/casting/` (registry/history/policy JSONs), `.ai-team/decisions/inbox/` (drop-box), `templates/` (format guides). - -### Session Summaries - -- **Sprint Plan 009 — Feasibility Review (2026-02-09)** — 📌 Team update (2026-02-08): Fenster revised sprint estimates: forwardability 6h (not 4h), export/import 11-14h (not 6h). Recommends export Sprint 2, i -- **File System Integrity Audit (2026-02-09)** -- **Upgrade Subcommand Implementation (2026-02-09)** — 📌 Team update (2026-02-08): V1 test suite shipped by Hockney — 12 tests pass. Action: when require.main guard is added to index.js, update test/index. -- **GitHub-Only Distribution (2026-02-09)** — ## Team Updates -- **Error Handling Implementation (Sprint Task 1.1)** -- **Version Stamping Phase 1 (Sprint Task 1.4)** — 📌 Team update (2026-02-08): CI pipeline created — GitHub Actions runs tests on push/PR to main/dev. PRs now have automated quality gate. — decided by -- **PR #2 Integration (2026-02-09)** — 📌 Team update (2026-02-09): If ask_user returns < 10 characters, treat as ambiguous and re-confirm — platform may fabricate default responses from bla -- **Smart Upgrade with Migration Registry (Sprint Task 2.2)** -- **Export CLI Implementation (Sprint Task 2.4)** -- **Import CLI Implementation (Sprint Task 3.1)** — 📌 Team update (2026-02-09): Tiered response modes shipped — Direct/Lightweight/Standard/Full modes replace uniform spawn overhead. Agents may now be s - -## Recent Updates - -📌 **Team update (2026-02-22):** PRD 16 shipped — Full init command implementation ported from beta CLI to squad-sdk TypeScript. Copies 34 template files, installs squad.agent.md with version stamping, detects project type (npm/go/python/java/dotnet), generates workflows (project-type-aware stubs for non-npm), creates directory structure (.squad/ with .ai-team/ legacy support), copies starter skills, scaffolds identity files (now.md, wisdom.md), appends .gitattributes merge=union rules and .gitignore log exclusions. Zero-dep, async/await, idempotent (never overwrites user state), Windows-compatible. PR #175 opened. — Fenster - -📌 **Team update (2026-02-21):** PRD 15 shipped — CLI entry point with full subcommand routing implemented in squad-sdk. Zero-dep color/emoji output utilities, error handling (fatal), squad directory detection (.squad/ with .ai-team/ legacy fallback), and subcommand stubs for all 9 commands (init, upgrade, watch, export, import, plugin, copilot, scrub-emails). Each stub prints helpful placeholder message with PRD reference. PR #173 opened on bradygaster/squad-pr. — Fenster - -📌 Team update (2026-02-20): Recruitment wave complete. Three new team members hired: Edie (TypeScript Engineer), Rabin (Distribution Engineer), Fortier (Node.js Runtime Dev). All onboarded with assessments. Keaton created 19 issues, 3 milestones, 12 labels on bradygaster/squad-pr. Kujan delivered feature risk punch list (14 GRAVE, 12 AT RISK, 28 COVERED, 5 INTENTIONAL). — decided by Keaton, Kujan, Edie, Rabin, Fortier - -📌 Team update (2026-02-13): VS Code runSubagent spawning — platform parity and adaptation strategy (consolidated). runSubagent viable with platform detection and custom .agent.md files. Spawn patterns all map 1:1; model selection is the gap; recommendation: prompt-level platform detection, no abstraction layer. Unblocks #32-35. — decided by Keaton, Strausz, Kujan -📌 Team update (2026-02-13): MCP integration — coordinator awareness and CLI config generation. Added MCP Integration section to squad.agent.md, MCP context block to spawn template, and `.copilot/mcp-config.json` sample generation to `squad init` and `squad upgrade`. Issue #11 resolved. — decided by Fenster -📌 Team update (2026-02-09): No npm publish — GitHub-only distribution. Kobayashi hired as Git & Release Engineer. Release plan (021) filed. Sprint plan 019a amended: item 1.8 cancelled, items 1.11-1.13 added. -📌 Team update (2026-02-08): CI pipeline created — GitHub Actions runs tests on push/PR to main/dev. PRs now have automated quality gate. — decided by Hockney -📌 Team update (2026-02-08): Coordinator now captures user directives to decisions inbox before routing work. Directives persist to decisions.md via Scribe. — decided by Kujan -📌 Team update (2026-02-08): Coordinator must acknowledge user requests with brief text before spawning agents. Single agent gets a sentence; multi-agent gets a launch table. — decided by Verbal -📌 Team update (2026-02-08): Hockney expanded tests to 27 (7 suites), including coverage for fatal(), error handling, and validation. — decided by Hockney -📌 Team update (2026-02-08): Silent success mitigation strengthened in all spawn templates — 6-line RESPONSE ORDER block + filesystem-based detection. — decided by Verbal -📌 Team update (2026-02-08): .ai-team/ must NEVER be tracked in git on main. Three-layer protection: .gitignore, package.json files allowlist, .npmignore. — decided by Verbal -📌 Team update (2026-02-08): Incoming queue architecture finalized — SQL hot layer + filesystem durable store, team backlog as third memory channel, agent cloning ready. — decided by Verbal -📌 Team update (2026-02-09): If ask_user returns < 10 characters, treat as ambiguous and re-confirm — platform may fabricate default responses from blank input. — decided by Brady -📌 Team update (2026-02-09): PR #2 architectural review completed — 3 must-fixes, 5 should-fixes. All must-fixes applied during integration. — decided by Keaton -📌 Team update (2026-02-09): Documentation structure formalized — docs/ is user-facing only, team-docs/ for internal, .ai-team/ is runtime state. Three-tier separation is permanent. — decided by Kobayashi -📌 Team update (2026-02-09): Per-agent model selection designed — 4-layer priority (user override → charter → registry → auto-select). Role-to-model mapping: Designer→Opus, Tester/Scribe→Haiku, Lead/Dev→Sonnet. — decided by Verbal -📌 Team update (2026-02-09): Tiered response modes shipped — Direct/Lightweight/Standard/Full modes replace uniform spawn overhead. Agents may now be spawned with lightweight template (no charter/history/decisions reads) for simple tasks. — decided by Verbal -📌 Team update (2026-02-09): Skills Phase 1 + Phase 2 shipped — agents now read SKILL.md files before working and can write SKILL.md files from real work. Skills live in .ai-team/skills/{name}/SKILL.md. Confidence lifecycle: low→medium→high. — decided by Verbal -📌 Team update (2026-02-09): docs/ and CHANGELOG.md now included in release pipeline (KEEP_FILES, KEEP_DIRS, package.json files, .npmignore updated). Brady's directive. — decided by Kobayashi -📌 Team update (2026-02-20): SDK replatform 14 PRDs documented + master index. Adapter layer isolates SDK coupling. PRD 1 (runtime) is the gate. Coordinator shrinks to 12-15KB. compareSemver() fixed for pre-release suffixes (0.5.3-insiders). — decided by Keaton, Fenster, Verbal, Kujan, Baer - - -📌 Team update (2026-02-09): Preview branch added to release pipeline — two-phase workflow: preview then ship. Brady eyeballs preview before anything hits main. — decided by Kobayashi - -📌 Team update (2026-02-10): v0.3.0 sprint plan approved — per-agent model selection, team backlog, Demo 1. — decided by Keaton - -📌 Team update (2026-02-13): SSH workaround documentation pattern merged to decisions.md — inline README workarounds + troubleshooting.md guide, no code workarounds. — decided by Fenster - - -📌 Team update (2026-02-10): Marketing site architecture consolidated — Jekyll on GitHub Pages, docs/ is source root, blog from team-docs/blog/, no content reproduction. McManus (content) + Fenster (infrastructure) for Phase 1. — decided by bradygaster, Keaton, McManus -📌 Team update (2026-02-10): GitHub Issues/PR integration must not break CLI conversations — CLI is primary surface, GitHub integration is additive only. — decided by bradygaster - - -📌 Team update (2026-02-10): 0.3.0 priorities: async comms > GitHub-native > CCA adoption — decided by bradygaster - -📌 Team update (2026-02-10): Clean branch config at init time — filter squad state from designated branches — decided by bradygaster - -📌 Team update (2026-02-10): `squad:` label convention standardized for GitHub Issues — decided by Keaton, McManus - - -📌 Team update (2026-02-10): Async comms strategy decided — two-tier MVP: CCA-as-squad-member (2-4h, prompt-only) + Telegram bridge (8-16h, conditional on SDK spike). CCA is the floor. — decided by Kujan - -## Learnings - -- **Provider abstraction belongs at the prompt level, not in index.js.** The coordinator is a prompt that executes shell commands. A JavaScript provider module would require index.js to be a runtime (it's an installer) and would double the maintenance surface. Command templates in squad.agent.md are the correct abstraction layer. -- **index.js has near-zero GitHub-platform coupling.** The `.github/agents/` path is a Copilot CLI convention, not GitHub-the-platform. The only GitHub-specific code is the `npx github:bradygaster/squad` usage string (cosmetic). All real platform coupling is in squad.agent.md. -- **Capability negotiation is critical for multi-provider support.** ADO has no labels (uses Tags), no reactions, and requires work item types. GitLab has no sub-issues. The provider interface must declare what's available so the coordinator can adapt. -- **Two-channel pattern (MCP read, gh CLI write) is GitHub-specific, not universal.** Future providers will likely be CLI-only. The MCP fallback logic should be inside the GitHub provider, not in the generic interface. -- **Git remote URL parsing covers 95% of provider detection.** `github.com` → GitHub, `dev.azure.com`/`visualstudio.com` → ADO, `gitlab.com` → GitLab. Self-hosted instances need CLI-based detection (is `glab` configured?). Generic is the fallback. -- **ADO is the hardest provider.** WIQL for search, Tags for labels, Iterations for milestones, Work Item Types for issues — every concept has an impedance mismatch. GitLab is the easiest (glab mirrors gh closely). Estimate: ADO 23h, GitLab 12h, GitHub reorganization 9h. -- **Project type detection via marker files (issue #87).** `detectProjectType(dir)` checks for `package.json` (npm), `go.mod` (go), `requirements.txt`/`pyproject.toml` (python), `pom.xml`/`build.gradle` (java), `*.csproj`/`*.sln` (dotnet), falling back to `unknown`. Five project-type-sensitive workflows (`squad-ci`, `squad-release`, `squad-preview`, `squad-insider-release`, `squad-docs`) get stubs with TODO comments for non-npm projects. Six GitHub-API-only workflows always copy verbatim. Tests updated to add `package.json` in temp dirs where byte-for-byte template match is asserted (that test is semantically "npm project gets verbatim copy"). All 72 tests pass. - -📌 Team update (2026-02-20): Issues #86 & #87 sprint complete. Git Checkout Safety (Verbal): Added Git Safety rules to spawn templates and Fenster charter. Hockney: Wrote 8 regression tests for uncommitted-change protection. Project Type Detection (Fenster): Implemented `detectProjectType()` in index.js with marker file detection; workflow generation now stubs non-npm types with helpful TODO comments. All 72 tests pass. — decided by Verbal, Hockney, Fenster - -📌 Team update (2026-02-10): v0.3.0 is ONE feature — proposals as GitHub Issues. All other items deferred. — decided by bradygaster - -📌 Team update (2026-02-10): Actions automation ships as opt-in templates in templates/workflows/, 3 workflows in v0.3.0. — decided by Keaton, Kujan - -📌 Team update (2026-02-10): Label taxonomy (39 labels, 7 namespaces) drives entire GitHub-native workflow. — decided by bradygaster, Verbal - -📌 Team update (2026-02-10): CCA governance must be self-contained in squad.agent.md (cannot read .ai-team/). — decided by Kujan - -📌 Team update (2026-02-10): Proposal migration uses three-wave approach — active first, shipped second, superseded/deferred last. — decided by Keaton - - -📌 Team update (2026-02-11): Project boards consolidated — v0.4.0 target confirmed, gh CLI (not npm), opt-in only, labels authoritative over boards. Community triage responses must use substantive technical detail. — decided by Keaton, Kujan - -📌 Team update (2026-02-11): Per-agent model selection implemented with cost-first directive (optimize cost unless writing code) — decided by Brady and Verbal - -📌 Team update (2026-02-11): Discord is the v0.3.0 MVP messaging connector. Gateway must be platform-agnostic with zero GitHub-specific imports. — decided by Keaton - -- **UTF-8 emoji mojibake in test file.** `test/index.test.js` had 8 instances of garbled emoji strings (e.g. `≡ƒæñ` instead of `👤`, `≡ƒôî` instead of `📌`, `≡ƒñû` instead of `🤖`, `≡ƒƒó`/`≡ƒƒí`/`≡ƒö┤` instead of `🟢`/`🟡`/`🔴`). Root cause: file was likely saved or transferred through a system that re-encoded UTF-8 multibyte sequences as Latin-1/CP1252. Fixed all 8 instances to use real Unicode codepoints matching what `index.js` and `squad.agent.md` produce. All 118 tests pass. - -- **Universe allowlist expansion (issue #21).** Added Adventure Time (community request from Gabe) plus 10 new universes to the allowlist in both `.github/agents/squad.agent.md` and `.ai-team/casting/policy.json`. New universes: Futurama, Seinfeld, The Office, Cowboy Bebop, Fullmetal Alchemist, Stranger Things, The Expanse, Arcane, Ted Lasso, Dune. Selection rationale: filled genre gaps (sitcom, anime, animation, workplace comedy, hard sci-fi, sports/comedy). Total universes went from 20 → 31. Constraints added for The Office (avoid Michael Scott at scale) and Dune (combine book/film, avoid Paul unless required). Closed issue #21. - - -📌 Team update (2026-02-12): Universe expansion complete — 11 new universes (Adventure Time, Futurama, Seinfeld, The Office, Cowboy Bebop, Fullmetal Alchemist, Stranger Things, The Expanse, Arcane, Ted Lasso, Dune) added to casting allowlist. Issue #21 closed. — decided by Fenster - -- **SSH agent / npm spinner hang documented (issue #30).** `npx github:bradygaster/squad` resolves via `git+ssh://`. When no SSH agent is running, git prompts for a passphrase but npm's progress spinner overwrites the TTY prompt, making it look frozen. This is an npm bug, not ours. Documented workarounds in README (Install section note + Known Limitations bullet) and created `docs/scenarios/troubleshooting.md` with problem→cause→fix format covering SSH hang, gh auth, Node version, agent visibility, upgrade cache, and Windows paths. The troubleshooting doc pattern is reusable for future community-reported issues. - -- **Label automation for go: and release: namespaces.** Created `squad-label-enforce.yml` workflow to enforce mutual exclusivity on `go:*` (triage verdict) and `release:*` (version target) labels. When a new label is applied, conflicting labels in the same namespace are auto-removed and a comment is posted (only if a change was made). Special cases: applying `go:yes` auto-adds `release:backlog` if no release target exists; applying `go:no` removes all release labels. Updated `sync-squad-labels.yml` to sync 3 go: labels (go:yes, go:no, go:needs-research) and 5 release: labels (release:v0.4.0, v0.5.0, v0.6.0, v1.0.0, release:backlog). Updated `squad-triage.yml` to apply `go:needs-research` as default verdict after triage assigns a squad member. Updated `squad-heartbeat.yml` to add two new checks: issues missing go: labels and go:yes issues missing release: labels. This implements "agentic DevOps" — labels drive automation, automation enforces label integrity. -📌 Team update (2026-02-13): Agent Progress Updates — Milestone Signals + Coordinator Polling mechanism. 30s polling loop extracts [MILESTONE] markers from agent output. No agent code changes. Backward compatible. Unlocks notifications + Squad DM integration. — decided by Keaton -📌 Team update (2026-02-14): VS Code Model & Background Parity — Phase 1 (v0.4.0): accept session model, use runSubagent. Phase 2 (v0.5.0): generate model-tier agent files. runSubagent lacks model param; use prompt-level detection in squad.agent.md. — decided by Kujan -📌 Team update (2026-02-15): VS Code File Discovery — Works with zero code changes. Instruction-level abstraction naturally cross-platform. Constraints: single-root workspaces only, workspace trust required, tool approval UX on first write. — decided by Strausz - -- **GitHub Projects V2 — Phase 1 validation complete (WI-1 + WI-2, Issue #6).** All `gh project *` CLI commands validated live against bradygaster/squad. Created test board, discovered field IDs, added issue #6, moved between all status columns (Todo→In Progress→Done), archived, linked to repo, deleted. Key findings: (1) Zero dependencies confirmed — no GraphQL client needed, `gh project` wraps everything. (2) `project` scope already present on token. (3) 4-step field discovery pipeline works — field IDs are project-specific but stable. (4) `item-add` is idempotent. (5) `item-edit` requires 4 opaque IDs (project, item, field, option) — most complex command. (6) Windows works via PowerShell `ConvertFrom-Json` instead of `jq`. Created SKILL.md at `.ai-team/skills/github-projects-v2-commands/SKILL.md` and implementation proposal at `team-docs/proposals/006a-project-board-implementation.md`. Provider abstraction documented: GitHub (implemented), ADO/GitLab (stubbed). Phase 1 gate passed — Phase 2 unblocked. Posted findings to issue #6. - -📌 Team update (2026-02-15): Projects V2 Phase 1 validated — `gh project *` CLI commands work for all board operations. SKILL.md + implementation proposal shipped. Phase 2 (coordinator prompts + label sync workflow) unblocked. — decided by Fenster - - -📌 Team update (2026-02-13): Projects V2 Phase 1 validation complete — all gh project * commands validated live, no npm dependencies needed. Unblocks WI-3 (board init), WI-4 (label-to-board sync), WI-5 (board query). — decided by Fenster - -- **MCP integration shipped (#11).** Added MCP Integration section to squad.agent.md (after Client Compatibility, before Eager Execution): detection via tool prefix scanning, routing rules (coordinator direct vs spawn with context), graceful degradation (CLI fallback → inform user → continue without), config file locations, Trello sample config. References the existing MCP skill at `.ai-team/skills/mcp-tool-discovery/SKILL.md` instead of duplicating it. Updated spawn template with optional MCP TOOLS AVAILABLE block. Added MCP config generation to `squad init` (creates `.copilot/mcp-config.json` sample with `EXAMPLE-trello` prefix pattern). Added 0.4.0 upgrade migration so existing installs get the sample config on `squad upgrade`. Both init and migration are idempotent (skip if file exists). - -- **Docs template extraction — inline→external files.** Refactored `docs/build.js` to read HTML template, CSS, and JS from external files instead of generating them inline via `getCSS()`, `getJS()`, and `getTemplate()` string-building functions. Created `docs/assets/template.html` (HTML shell with `{{title}}`, `{{nav}}`, `{{content}}`, `{{searchIndex}}`, `{{basePath}}` placeholders), `docs/assets/style.css`, and `docs/assets/script.js`. Build reads template once at startup, does placeholder replacement per page. CSS/JS are linked externally (`` / ` - - - diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 000000000..ab9860bd3 --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,20 @@ +import { defineConfig } from 'astro/config'; +import tailwindcss from '@tailwindcss/vite'; +import { remarkRewriteLinks } from './src/plugins/remark-rewrite-links.mjs'; + +export default defineConfig({ + site: 'https://bradygaster.github.io', + base: '/squad/', + vite: { + plugins: [tailwindcss()], + }, + markdown: { + remarkPlugins: [remarkRewriteLinks], + shikiConfig: { + themes: { + light: 'github-light', + dark: 'github-dark', + }, + }, + }, +}); diff --git a/docs/build.js b/docs/build.js deleted file mode 100644 index 24e9b95d1..000000000 --- a/docs/build.js +++ /dev/null @@ -1,361 +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: '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'], - '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'], -}; - -// 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..cebb2c48f --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,6228 @@ +{ + "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.34.5", + "tailwindcss": "^4.1.0", + "unist-util-visit": "^5.1.0" + }, + "devDependencies": { + "pagefind": "^1.4.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", + "engines": { + "node": ">=18" + } + }, + "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/@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/@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/@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/@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/@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/@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.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/@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/@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/@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/@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/@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/@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.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/@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/@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/@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/@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/@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.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/@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/@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/@pagefind/darwin-arm64": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.4.0.tgz", + "integrity": "sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/darwin-x64": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.4.0.tgz", + "integrity": "sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/freebsd-x64": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.4.0.tgz", + "integrity": "sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@pagefind/linux-arm64": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.4.0.tgz", + "integrity": "sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/linux-x64": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.4.0.tgz", + "integrity": "sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/windows-x64": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.4.0.tgz", + "integrity": "sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "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/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/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-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/pagefind": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.4.0.tgz", + "integrity": "sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==", + "dev": true, + "license": "MIT", + "bin": { + "pagefind": "lib/runner/bin.cjs" + }, + "optionalDependencies": { + "@pagefind/darwin-arm64": "1.4.0", + "@pagefind/darwin-x64": "1.4.0", + "@pagefind/freebsd-x64": "1.4.0", + "@pagefind/linux-arm64": "1.4.0", + "@pagefind/linux-x64": "1.4.0", + "@pagefind/windows-x64": "1.4.0" + } + }, + "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.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "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/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/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..51b4d5702 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,22 @@ +{ + "name": "squad-docs", + "type": "module", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build && npx pagefind --site dist", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.0", + "astro": "^5.7.0", + "sharp": "^0.34.5", + "tailwindcss": "^4.1.0", + "unist-util-visit": "^5.1.0" + }, + "devDependencies": { + "pagefind": "^1.4.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/specs/streams-prd.md b/docs/specs/streams-prd.md deleted file mode 100644 index 30b017489..000000000 --- a/docs/specs/streams-prd.md +++ /dev/null @@ -1,138 +0,0 @@ -# Workstreams PRD — Product Requirements Document - -> Scaling Squad across multiple Codespaces via labeled workstreams. - -## 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 workstreams, validating the approach. However, the manual coordination was error-prone and needed to be automated. - -## Requirements - -### Must Have (P0) - -- [ ] **Workstream Definition**: Define workstreams in `.squad/workstreams.json` with name, label filter, folder scope, and workflow -- [ ] **Workstream Resolution**: Automatically detect active workstream from env var, file, or config -- [ ] **Label Filtering**: Ralph only triages issues matching the workstream's label -- [ ] **Folder Scoping**: Agents restrict modifications to workstream's folder scope -- [ ] **CLI Management**: `squad workstreams list|status|activate` commands -- [ ] **Init Integration**: `squad init` optionally generates workstreams config -- [ ] **Agent Template**: squad.agent.md includes workstream awareness instructions - -### Should Have (P1) - -- [ ] **Workstream Status Dashboard**: Show PR/branch activity per workstream -- [ ] **Conflict Detection**: Warn when workstreams 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 workstreams -- [ ] **Cross-workstream dependencies**: Track and resolve inter-workstream blockers -- [ ] **Workstream metrics**: Throughput, cycle time, merge conflict rate per workstream - -## Design Decisions - -### 1. GitHub Labels as the Partition Key - -**Decision**: Use GitHub labels (e.g., `team:ui`) to partition work across workstreams. - -**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 Workstream 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 workstream. - -### 4. Synthesized Definitions for Unknown Workstreams - -**Decision**: When `SQUAD_TEAM` or `.squad-workstream` specifies a workstream 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 `workstreams.json` first. The convention of `team:{name}` is predictable and consistent. - -## Design Clarifications - -### Overlapping Folder Scope - -**Multiple workstreams 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 workstreams. Preventing access would break legitimate work. -- **Interface contracts**: Backend and Frontend workstreams both need to update shared type definitions. -- **Branch isolation handles it**: Since each issue gets its own branch (`squad/{issue}-{slug}`), two workstreams editing the same file won't conflict until merge time — and Git resolves non-overlapping changes automatically. - -**When it breaks**: Semantic conflicts — two workstreams 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 workstreams have open PRs touching the same file. Surface this in `squad workstreams status`. - -### Single-Machine Multi-Workstream - -**One machine can serve multiple workstreams to save costs.** Instead of 1 Codespace per workstream: - -```bash -# Sequential switching -squad workstreams activate ui-team # Ralph works team:ui issues -# ... switch when done ... -squad workstreams activate backend-team # now works team:backend issues -``` - -**v2: Round-robin mode** — Ralph cycles through workstreams automatically: -```json -{ - "workstreams": [...], - "mode": "round-robin", - "issuesPerWorkstream": 3 -} -``` - -| Approach | Cost | Speed | Isolation | -|----------|------|-------|-----------| -| 1 Codespace per workstream | 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 "workstream" only determines which issues Ralph picks up. - -## Future Work - -### Meta-Coordinator - -A "coordinator of coordinators" that: -- Monitors all workstreams for cross-cutting concerns -- Detects when one workstream's work blocks another -- Suggests label assignments for ambiguous issues -- Produces a unified status dashboard - -### Cross-Workstream Dependencies - -Track when a workstream needs work from another workstream: -- Automated detection via import graphs -- Cross-workstream issue linking -- Priority escalation for blocking dependencies - -### Workstream Templates - -Pre-built workstream configurations for common architectures: -- **Frontend/Backend** — 2 workstreams for web apps -- **Monorepo** — 1 workstream per package -- **Microservices** — 1 workstream per service -- **Feature teams** — dynamic workstreams per feature area diff --git a/docs/assets/squad-logo.png b/docs/src/assets/images/squad-logo.png similarity index 100% rename from docs/assets/squad-logo.png rename to docs/src/assets/images/squad-logo.png diff --git a/docs/src/components/Footer.astro b/docs/src/components/Footer.astro new file mode 100644 index 000000000..f44ae621e --- /dev/null +++ b/docs/src/components/Footer.astro @@ -0,0 +1,55 @@ +--- +import { Image } from 'astro:assets'; +import squadLogo from '../assets/images/squad-logo.png'; +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..c553ea458 --- /dev/null +++ b/docs/src/components/Header.astro @@ -0,0 +1,107 @@ +--- +import { Image } from 'astro:assets'; +import ThemeToggle from './ThemeToggle.astro'; +import Search from './Search.astro'; +import squadLogo from '../assets/images/squad-logo.png'; +const base = import.meta.env.BASE_URL; +const pathname = Astro.url.pathname; +const isDocsActive = pathname.startsWith(`${base}docs/`); +const isBlogActive = pathname.startsWith(`${base}blog/`); + +const navBase = "px-3 py-1.5 rounded-md transition-colors"; +const navInactive = "text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-white hover:bg-surface-100 dark:hover:bg-surface-800"; +const navActive = "text-squad-700 dark:text-squad-300 bg-squad-50 dark:bg-squad-900/30 font-medium"; + +const mobileNavBase = "block px-3 py-2 rounded-md text-base transition-colors"; +--- + +
+
+ + + + + + + + + Squad + Squad + + + + + + +
+ + + +
+
+ + + +
+ + diff --git a/docs/src/components/Search.astro b/docs/src/components/Search.astro new file mode 100644 index 000000000..f756cc81e --- /dev/null +++ b/docs/src/components/Search.astro @@ -0,0 +1,156 @@ +--- +const base = import.meta.env.BASE_URL; +--- + +
+ +
+ + + + + diff --git a/docs/src/components/Sidebar.astro b/docs/src/components/Sidebar.astro new file mode 100644 index 000000000..7b5ccc392 --- /dev/null +++ b/docs/src/components/Sidebar.astro @@ -0,0 +1,79 @@ +--- +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 93% rename from docs/blog/021-the-migration.md rename to docs/src/content/blog/021-the-migration.md index 17cbaa550..eafc2c838 100644 --- a/docs/blog/021-the-migration.md +++ b/docs/src/content/blog/021-the-migration.md @@ -172,7 +172,7 @@ I'm starting a new project. Here's what I'm building: a React + Node API with us Squad proposes a team (Lead, Frontend, Backend, Tester, Scribe), you say yes, and they're ready. Describe the work. They execute it. Messages, decisions, and history persist in `.squad/` — commit it, share it, iterate on it. -**Full guide:** [`README.md`](../../README.md) | **Samples:** [`samples/`](../../samples/) +**Full guide:** [`README.md`](https://github.com/bradygaster/squad/blob/main/README.md) | **Samples:** [`samples/`](https://github.com/bradygaster/squad/tree/main/samples) ## The Version Jump: v0.5.4 → v0.8.18 @@ -183,13 +183,13 @@ You might notice the version leap. Here's why: - **v0.7.x** — Three development waves (orchestration, observability, docs) - **v0.8.x (current)** — Unified, public, semver-stable -You're not jumping over broken versions. You're joining the stable channel of a mature codebase. Read the [CHANGELOG.md](../../CHANGELOG.md) if you want the full arc. +You're not jumping over broken versions. You're joining the stable channel of a mature codebase. Read the [CHANGELOG.md](https://github.com/bradygaster/squad/blob/main/CHANGELOG.md) if you want the full arc. ## Links - **Public repository:** [`bradygaster/squad`](https://github.com/bradygaster/squad) - **Migration guide:** [`docs/get-started/migration.md`](../get-started/migration.md) -- **README with full install methods:** [`README.md`](../../README.md) +- **README with full install methods:** [`README.md`](https://github.com/bradygaster/squad/blob/main/README.md) - **Samples:** [`samples/`](../../samples/) — hello-squad, knock-knock, rock-paper-scissors, streaming-chat, hook-governance, and more - **Getting started guide:** `docs/guide/getting-started.md` (coming soon) 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 99% rename from docs/blog/022-welcome-to-the-new-squad.md rename to docs/src/content/blog/022-welcome-to-the-new-squad.md index 01f457bc7..ee2ff28ec 100644 --- a/docs/blog/022-welcome-to-the-new-squad.md +++ b/docs/src/content/blog/022-welcome-to-the-new-squad.md @@ -788,7 +788,7 @@ Start building. - **SDK on npm:** [@bradygaster/squad-sdk](https://www.npmjs.com/package/@bradygaster/squad-sdk) - **CLI on npm:** [@bradygaster/squad-cli](https://www.npmjs.com/package/@bradygaster/squad-cli) - **Migration Guide:** [docs/get-started/migration.md](../get-started/migration.md) -- **Samples:** [samples/README.md](../../samples/README.md) +- **Samples:** [samples/README.md](https://github.com/bradygaster/squad/blob/main/samples/README.md) - **Issues:** [github.com/bradygaster/squad/issues](https://github.com/bradygaster/squad/issues) --- diff --git a/docs/blog/023-workstreams-horizontal-scaling.md b/docs/src/content/blog/023-subsquads-horizontal-scaling.md similarity index 61% rename from docs/blog/023-workstreams-horizontal-scaling.md rename to docs/src/content/blog/023-subsquads-horizontal-scaling.md index c15a9025a..545406f04 100644 --- a/docs/blog/023-workstreams-horizontal-scaling.md +++ b/docs/src/content/blog/023-subsquads-horizontal-scaling.md @@ -1,133 +1,133 @@ ---- -title: "Workstreams — Scaling Squad Across Multiple Codespaces" -date: 2026-03-05 -author: "Tamir Dresher (Community Contributor)" -wave: null -tags: [squad, workstreams, scaling, codespaces, horizontal-scaling, multi-instance, community] -status: draft -hero: "Squad Workstreams lets you partition a repo's work across multiple Codespaces — each running its own scoped Squad instance. One repo, multiple AI teams, zero conflicts." ---- - -# Workstreams — 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 Workstreams. - -## What Are Workstreams? - -Workstreams partition your repo's issues into labeled subsets. Each Codespace (or machine) runs one workstream, 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 workstream's label. │ -└─────────────────────────────────────────────────┘ -``` - -## How It Works - -**1. Define workstreams** in `.squad/workstreams.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 workstream:** - -```bash -# Via environment variable (ideal for Codespaces) -export SQUAD_TEAM=bridge - -# Or via CLI (local machines) -squad workstreams 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 | Workstream | 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 workstreams list # Show all configured workstreams -squad workstreams status # Activity per workstream (branches, PRs) -squad workstreams activate X # Activate a workstream for this machine -``` - -## Resolution Chain - -Squad resolves the active workstream in priority order: - -1. `SQUAD_TEAM` environment variable -2. `.squad-workstream` file (written by `activate`, gitignored) -3. Auto-select if exactly one workstream is defined -4. No workstream → 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 `workstreams.json` work exactly as before -- **Single-machine testing** — use `squad workstreams activate` to switch workstreams sequentially without needing multiple Codespaces - -## What's Next - -We're looking at cross-workstream coordination — a central dashboard showing all workstreams' activity, conflict detection for shared files, and auto-merge coordination. See the [PRD](https://github.com/bradygaster/squad/issues/200) for the full roadmap. - -Also: we haven't settled on the name yet! "Workstreams" is the working title, but we're considering alternatives like "Lanes", "Teams", or "Streams". If you have an opinion, let us know in the [discussion](https://github.com/bradygaster/squad/issues/200). - -## Try It - -```bash -# Install Squad -npm install -g @bradygaster/squad-cli - -# Init in your repo -squad init - -# Create workstreams.json and label your issues -# Then activate and go -squad workstreams activate frontend -squad start -``` - -Full docs: [Scaling with Workstreams](../scenarios/scaling-workstreams.md) | [Multi-Codespace Setup](../scenarios/multi-codespace.md) | [Workstreams 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](https://github.com/bradygaster/squad/blob/main/docs/_internal/specs/streams-prd.md) diff --git a/docs/blog/024-v0822-release.md b/docs/src/content/blog/024-v0823-release.md similarity index 91% rename from docs/blog/024-v0822-release.md rename to docs/src/content/blog/024-v0823-release.md index 443158857..efbfdd6a0 100644 --- a/docs/blog/024-v0822-release.md +++ b/docs/src/content/blog/024-v0823-release.md @@ -1,18 +1,18 @@ --- -title: "v0.8.22 Release: SDK-First Mode, Critical Fixes, and Production Stability" +title: "v0.8.23 Release: Node 24+ Compatibility, Squad RC Docs, and Critical Fixes" date: 2026-03-10 author: "McManus (DevRel)" wave: 7 -tags: [squad, release, v0.8.22, sdk-first, stability, cli, typescript, azure-functions] +tags: [squad, release, v0.8.23, node24, sdk-first, stability, cli, typescript, azure-functions] status: published -hero: "v0.8.22 introduces SDK-First Mode for type-safe team configuration, resolves critical installation crashes, and delivers production-grade stability with 3,724 passing tests. Define your AI team in TypeScript, deploy anywhere." +hero: "v0.8.23 fixes a critical crash when running `squad init` on Node.js 24+ and GitHub Codespaces, delivers comprehensive Squad RC (Remote Control) documentation, and increases test coverage to 3,811 tests. Faster CLI startup for non-session commands." --- -# v0.8.22 Release: SDK-First Mode, Critical Fixes, and Production Stability +# v0.8.23 Release: Node 24+ Compatibility, Squad RC Docs, and Critical Fixes > ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. -> _v0.8.22 is a watershed release combining SDK-First Mode with critical stability improvements. Define your AI team in TypeScript with 8 builder functions, compile to markdown with `squad build`, and deploy anywhere. This release also eliminates installation crashes, wires missing CLI commands, fixes model configuration round-trips, and hardens the Windows test suite. 26 issues closed, 16 PRs merged, 3,724 tests passing._ +> _v0.8.23 is a critical hotfix addressing a crash when running `squad init` on Node.js 24+ and GitHub Codespaces. It ships comprehensive Squad RC documentation, introduces lazy module loading for faster CLI startup, and includes a postinstall patch for ESM import issues. 2 issues closed, 3 PRs merged, 3,811 tests passing._ --- @@ -445,7 +445,7 @@ All 8 telemetry modules (`defineHooks`, `defineTelemetry`, meter providers, span - 2 Windows EBUSY race condition tests (fs.rm retry logic) - 13 known timeout flakes on Windows (non-logic, environment-related) -**Total test suite:** 3,724 passing tests (3,740 total, 0 logic failures) +**Total test suite:** 3,811 passing tests (3,840 total, 0 logic failures) --- @@ -465,6 +465,28 @@ All 8 telemetry modules (`defineHooks`, `defineTelemetry`, meter providers, span --- +## Node 24+ Compatibility Fix + +v0.8.23 fixes a critical crash when running `squad init` on Node.js 24+ (including GitHub Codespaces): + +``` +Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'vscode-jsonrpc/node' +``` + +The root cause was an upstream ESM import issue in `@github/copilot-sdk`. Squad now uses a two-layer defense: +- **Lazy imports** — commands like `init`, `build`, `link`, and `migrate` no longer eagerly load copilot-sdk +- **Postinstall patch** — automatically fixes the broken import at install time + +This also means CLI startup is faster for non-session commands. + +--- + +## Squad RC Documentation + +Comprehensive documentation for `squad rc` (Remote Control) is now available. The new guide covers ACP passthrough architecture, the 7-layer security model, mobile keyboard shortcuts, and troubleshooting. See [Squad RC](../features/squad-rc.md). + +--- + ## What's Coming Next ### v0.8.23 (Roadmap) @@ -635,8 +657,8 @@ npx squad start - [SDK-First Mode Guide](../sdk-first-mode.md) - [SDK Reference](../reference/sdk.md) - [Azure Function Sample](../../samples/azure-function-squad/) -- [Remote Squad Mode Docs](../remote-squad-mode.md) -- [CHANGELOG](../../CHANGELOG.md) +- [Remote Squad Mode Docs](../features/remote-control.md) +- [CHANGELOG](https://github.com/bradygaster/squad/blob/main/CHANGELOG.md) **Related Issues:** - #194 — SDK-First Mode diff --git a/docs/src/content/blog/025-squad-goes-enterprise-azure-devops.md b/docs/src/content/blog/025-squad-goes-enterprise-azure-devops.md new file mode 100644 index 000000000..498188143 --- /dev/null +++ b/docs/src/content/blog/025-squad-goes-enterprise-azure-devops.md @@ -0,0 +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) diff --git a/docs/src/content/blog/026-whats-new-ado-comms-subsquads.md b/docs/src/content/blog/026-whats-new-ado-comms-subsquads.md new file mode 100644 index 000000000..30cf45d3d --- /dev/null +++ b/docs/src/content/blog/026-whats-new-ado-comms-subsquads.md @@ -0,0 +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) diff --git a/docs/src/content/blog/027-v0825-release.md b/docs/src/content/blog/027-v0825-release.md new file mode 100644 index 000000000..92221c7a1 --- /dev/null +++ b/docs/src/content/blog/027-v0825-release.md @@ -0,0 +1,70 @@ +--- +title: "v0.8.25: Pre-Publish Quality Gate and CLI Smoke Testing" +date: 2026-03-08 +author: "PAO (DevRel)" +wave: 7 +tags: [squad, release, v0.8.25, testing, cli, quality, npm] +status: published +hero: "Squad now smoke-tests every CLI command in the packaged npm artifact before publishing." +--- + +# v0.8.25: Pre-Publish Quality Gate and CLI Smoke Testing + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +> _This release adds a critical pre-publish quality gate: 32 new tests that pack both `@bradygaster/squad-sdk` and `@bradygaster/squad-cli` into tarballs, install them in a clean temp directory, and verify all 27 CLI commands route correctly through the installed artifact. If a command is missing or broken in the tarball, the release is blocked._ + +--- + +## What Shipped + +### CLI Packaging Smoke Test + +The new test suite (`test/cli-packaging-smoke.test.ts`) simulates the exact npm install experience: + +1. **Pack** — Creates tarballs of both packages using `npm pack` +2. **Install** — Installs them in a clean isolated temp directory (just like `npm install -g` would) +3. **Verify routing** — Tests all 27 CLI commands through the installed artifact's bin entry +4. **Test aliases** — Validates 3 command aliases (watch, workstreams, remote-control) +5. **Error handling** — Tests --version, --help, and unknown command behavior + +**32 new tests. 3,963+ tests total.** + +### Pre-Publish CI Gate + +The `publish.yml` workflow now includes a `smoke-test` job that runs BEFORE both npm publish jobs. If the smoke test fails, nothing gets published. This blocks the exact class of bugs that bit us before: MODULE_NOT_FOUND errors, broken package.json exports, and ESM resolution failures. + +### Three-Layer Test Matrix + +This release completes a three-layer defense: + +| Layer | What it catches | Test file | +|-------|----------------|-----------| +| Source wiring | Import exists in code | `cli-command-wiring.test.ts` | +| Packaged artifact | Command works after npm pack + install | `cli-packaging-smoke.test.ts` (NEW) | +| Pre-publish gate | Blocks broken releases in CI | `publish.yml` smoke-test job (NEW) | + +Before this release, a command could exist in source code, pass all tests, and still be missing from the published npm package. That gap is now closed. + +--- + +## Why This Matters + +npm packages are built artifacts. The code you write isn't always the code users install. This test suite verifies that the packaged tarball — the actual bytes users download — works correctly. The squad's own quality agents (FIDO and EECOM) verified the release and gave unanimous GO. + +--- + +## Quick Stats + +- ✅ 32 new CLI packaging smoke tests +- ✅ 3,963+ tests passing, 150 test files +- ✅ Pre-publish CI gate added to `publish.yml` +- ✅ All 27 commands + 3 aliases verified in packaged artifact + +--- + +## 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) diff --git a/docs/src/content/blog/028-new-docs-site.md b/docs/src/content/blog/028-new-docs-site.md new file mode 100644 index 000000000..49de22a94 --- /dev/null +++ b/docs/src/content/blog/028-new-docs-site.md @@ -0,0 +1,109 @@ +--- +title: "New Docs Site: Built by the Community" +date: 2026-03-10 +author: "PAO (DevRel)" +wave: 7 +tags: [squad, docs, community, astro, contributions] +status: published +hero: "Squad's documentation gets a complete rebuild — powered by Astro, Tailwind CSS, and community contributors." +--- + +# New Docs Site: Built by the Community + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +> _Squad's documentation site has been completely rebuilt from the ground up. A full Astro-powered docs experience with search, responsive design, and content contributed by multiple community members._ + +--- + +## What Shipped + +### Complete Astro Docs Rewrite + +[@IEvangelist](https://github.com/IEvangelist) (David Pine) delivered a **complete documentation site rebuild** in PR #293. This isn't a reskin — it's a ground-up rewrite: + +- **Astro 5.7** — Static site generation with component islands +- **Tailwind CSS 4.1** — Modern utility-first styling with responsive design +- **Pagefind** — Client-side full-text search across all docs +- **Structured content** — Markdown content collections with frontmatter validation +- **Blog system** — All existing blog posts migrated into the new architecture +- **Custom components** — Sidebar with scroll-to-active, syntax-highlighted code blocks, callout boxes + +The site ships as a static build under `docs/` with its own `package.json`. Dev server: `npm run dev`. Production build: `astro build && pagefind`. + +### Docs Navigation Polish — PR #298 + +[@IEvangelist](https://github.com/IEvangelist) (David Pine) followed up with targeted improvements in PR #298: + +- **Active link highlighting** — Docs and Blog links now highlight in the top navigation when you're viewing that section +- **Favicon fixes** — Favicon asset handling improved for all browsers +- **Navigation clarity** — Users now have better visual feedback about where they are in the docs + +This was a fast-follow polish pass on the Astro rewrite, catching the details that make navigation feel solid. + +### Community Content from @diberry + +[@diberry](https://github.com/diberry) (Dina Berry) submitted **four pull requests** improving the getting-started experience: + +- **PR #286** — Added validation steps to the Quick Start README +- **PR #288** — "Which method should I use?" decision tree for the installation page — CLI, VS Code, or SDK, with clear guidance on when to use each +- **PR #290** — ".squad/ directory explainer" for the first-session guide — a table showing every file and directory in `.squad/` with its purpose, plus ownership guidance +- **PR #292** — Doc-impact review process added to team workflows + +All four contributions have been merged or ported into the new Astro docs structure. + +--- + +## What Changed for Users + +### Better Navigation + +The sidebar now scrolls to your current position when a page loads. If you're deep in the table of contents, it stays where you are instead of jumping back to the top. + +### Copilot CLI Callouts + +Key pages now include callouts directing users to the **GitHub Copilot CLI** as the recommended interface: + +``` +💡 The recommended way to use Squad is through GitHub Copilot CLI: +copilot --agent squad +``` + +### CI/CD Safety Warnings + +The CI/CD integration page now ships with the cron schedule **commented out by default** and a warning about GitHub Actions minutes consumption when enabling heartbeats and scheduled runs. + +--- + +## Community Impact + +This release represents a milestone for Squad's community. Two external contributors shaped the docs you'll use: + +| Contributor | Impact | +|-------------|--------| +| [@IEvangelist](https://github.com/IEvangelist) | Complete Astro docs site architecture and build | +| [@diberry](https://github.com/diberry) | Four PRs improving installation, getting-started, and team workflow docs | + +Both contributors are now credited in [CONTRIBUTORS.md](https://github.com/bradygaster/squad/blob/main/CONTRIBUTORS.md). + +--- + +## Try It + +Visit the docs at [bradygaster.github.io/squad](https://bradygaster.github.io/squad/) or run them locally: + +```bash +cd docs +npm install +npm run dev +``` + +Open [localhost:4321/squad/](http://localhost:4321/squad/) and explore. + +--- + +## What's Next + +- Search refinements and indexing improvements +- More scenario guides from community feedback +- Continued content contributions welcome — see [CONTRIBUTING.md](https://github.com/bradygaster/squad/blob/main/CONTRIBUTING.md) 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 93% rename from docs/community.md rename to docs/src/content/docs/community.md index 9f1a5363b..83e6f8eca 100644 --- a/docs/community.md +++ b/docs/src/content/docs/community.md @@ -13,13 +13,13 @@ Squad is built by contributors who believe in democratizing multi-agent developm We welcome contributions in all forms: -**For detailed contribution guidelines, including branch rules and PR process, see [CONTRIBUTING.md](../CONTRIBUTING.md).** +**For detailed contribution guidelines, including branch rules and PR process, see the [Contributing Guide](./guide/contributing.html).** ### Report Issues Found a bug, have a feature request, or want to discuss an idea? [Open an issue](https://github.com/bradygaster/squad/issues). ### Submit a Pull Request -Ready to contribute code? [Check out the open issues](https://github.com/bradygaster/squad/issues) and submit a PR. See [CONTRIBUTING.md](../CONTRIBUTING.md) for branch protection rules and the branch model. +Ready to contribute code? [Check out the open issues](https://github.com/bradygaster/squad/issues) and submit a PR. See the [Contributing Guide](./guide/contributing.html) for branch protection rules and the branch model. ### Join the Discussion Have questions, want to share how you're using Squad, or discuss the roadmap? [Start a discussion](https://github.com/bradygaster/squad/discussions). diff --git a/docs/src/content/docs/concepts/architecture.md b/docs/src/content/docs/concepts/architecture.md new file mode 100644 index 000000000..991891e3b --- /dev/null +++ b/docs/src/content/docs/concepts/architecture.md @@ -0,0 +1,70 @@ +# Architecture + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +How Squad works — one page, no handwaving. + +--- + +## System diagram + +``` +User request + ↓ +Coordinator (routing engine) + ↓ +Spawns agents in parallel + ↓ +Agents read memory (.squad/) → work → write results + ↓ +Scribe merges decisions, Ralph tracks issues + ↓ +Results returned to user +``` + +--- + +## Components + +### Coordinator + +The coordinator is Squad's routing engine. It reads your request, checks routing rules in `.squad/routing.md`, and decides which agents to spawn. If you say "team," it decomposes the work and launches multiple agents in parallel. If you name an agent, it routes directly to them. + +### Agents + +Each agent is a specialist with a charter, role, and persistent memory. Agents are spawned as independent subprocesses with their own context windows and tools. They read `.squad/decisions.md` and their own history before working, then write results back. Agents never see each other's conversations — the coordinator orchestrates coordination. + +### Memory (.squad/) + +All team state lives in `.squad/`. This includes the roster (`team.md`), routing rules (`routing.md`), decisions (`decisions.md`), agent charters and histories (`agents/`), and ceremony schedules (`ceremonies.md`). Agents read this before every spawn. You own these files — edit them anytime. + +### Routing + +Routing rules in `.squad/routing.md` define which agent handles which work. The coordinator reads these rules before spawning. You can override routing by naming an agent directly in your request. + +### Scribe + +The Scribe is a silent agent that tracks decisions and logs sessions. Every team has a Scribe. You never talk to them directly — they work in the background, merging decisions from all agents into `.squad/decisions.md`. + +### Ralph + +Ralph is the work monitor. He watches your GitHub or GitLab issues, tracks work in progress, and alerts the team when something is ready. Every team has a Ralph. He's silent unless you ask him for status. + +--- + +## What happens when you say "Team, build X"? + +1. **Coordinator reads the request** and checks `.squad/routing.md` for decomposition rules. +2. **Coordinator spawns multiple agents in parallel** — one for frontend, one for backend, one for tests, etc. +3. **Each agent reads `.squad/decisions.md`** and their own history (`agents/{name}/history.md`), then works independently. +4. **Agents write results** to their history files and propose decisions. +5. **Scribe merges all decisions** into `.squad/decisions.md`. +6. **Coordinator returns labeled results** to you, tagged with each agent's name. + +--- + +## Learn more + +- [**Work routing**](../features/routing) — How the coordinator decides which agents to spawn +- [**Memory and knowledge**](memory-and-knowledge) — How decisions, skills, and history persist +- [**Parallel work**](parallel-work) — How agents work simultaneously without conflicts 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 97% rename from docs/concepts/your-team.md rename to docs/src/content/docs/concepts/your-team.md index 6811cd886..63d0d18ad 100644 --- a/docs/concepts/your-team.md +++ b/docs/src/content/docs/concepts/your-team.md @@ -97,6 +97,8 @@ Sarah appears on the roster with a 👤 Human badge. When work routes to a human, Squad **pauses** and tells you someone needs to act. You relay the task outside of Squad, then report back what happened. Stale reminders keep things moving. +Not sure whether someone should be a roster member or just a normal GitHub collaborator? See [When to add a human member](../features/human-team-members.md#when-to-add-a-human-member) for a decision framework. + --- ## Work Routing diff --git a/docs/cookbook/recipes.md b/docs/src/content/docs/cookbook/recipes.md similarity index 98% rename from docs/cookbook/recipes.md rename to docs/src/content/docs/cookbook/recipes.md index 7deb6d423..d1f4f13ab 100644 --- a/docs/cookbook/recipes.md +++ b/docs/src/content/docs/cookbook/recipes.md @@ -217,4 +217,4 @@ What did the team accomplish last session? Any blockers? - [CLI Reference](../reference/cli.md) — Every command and config file - [SDK Reference](../reference/sdk.md) — Programmatic API -- [Migration & Troubleshooting](./migration.md) — Upgrades and fixes +- [Migration & Troubleshooting](../get-started/migration.md) — Upgrades and fixes 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/src/content/docs/features/distributed-mesh.md b/docs/src/content/docs/features/distributed-mesh.md new file mode 100644 index 000000000..795783131 --- /dev/null +++ b/docs/src/content/docs/features/distributed-mesh.md @@ -0,0 +1,298 @@ +# Distributed Mesh + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +**Try this to coordinate squads across machines:** +``` +Set up a distributed mesh so my local squad can see the state of our CI squad +``` + +**Try this to sync remote squad state:** +``` +Run sync-mesh.sh to pull the latest state from all remote squads +``` + +The distributed mesh lets squads on different machines coordinate through git and HTTP. Local squads read remote squad state after syncing it locally. + +--- + +## What Is the Distributed Mesh? + +One sentence: + +> **"The filesystem is the mesh, and git is how the mesh crosses machine boundaries."** + +Squad agents always read local files. When squads live on different machines, you need to materialize remote state locally before agents can see it. The distributed mesh does this through simple sync scripts — no servers, no federation protocols, no real-time messaging. + +--- + +## Three Zones + +| Zone | Description | Transport | Complexity | +|------|-------------|-----------|------------| +| **1 — Local** | Same host/filesystem | Direct file read | Zero | +| **2 — Remote-Trusted** | Different host, same org | `git pull` from shared repo | Zero new (git exists) | +| **3 — Remote-Opaque** | Different org, no shared auth | `curl` / HTTP fetch | ~15 lines of shell | + +**Zone 1 (Local):** `cat ../squad-b/SUMMARY.md` works because the file is on your disk. + +**Zone 2 (Remote-Trusted):** Squads push their state to a shared git repo. You pull from that repo to materialize their state locally. + +**Zone 3 (Remote-Opaque):** A remote organization publishes their squad's `SUMMARY.md` at an HTTPS URL. You curl it to materialize locally. + +--- + +## How It Works + +### Agent Lifecycle with Sync + +``` +Agent wakes up + │ + ├─ SYNC: git pull (Zone 2) + curl (Zone 3) + ├─ READ: cat .mesh/**/state.md — all local now + ├─ WORK: do the task + ├─ WRITE: update own billboard, log, drops + └─ PUBLISH: git push +``` + +Two new steps (SYNC, PUBLISH). Both are transport only — they move files, not change them. + +### What Doesn't Change + +- Agents read local files +- Write partitioning (each squad owns its directory) +- Pull-based coordination +- Eventual consistency +- LLMs as the relevance engine + +### What Changes + +Remote files need to arrive locally before agents can read them. + +--- + +## Configuration + +### The `mesh.json` File + +One JSON file lists where to find each squad: + +```json +{ + "squads": { + "auth-squad": { "zone": "local", "path": "../auth-squad/.mesh" }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "sync_to": ".mesh/remotes/ci-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.dev/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud" + } + } +} +``` + +### Sync Scripts + +**Bash (requires `jq` and `git`):** + +```bash +./sync-mesh.sh # reads mesh.json, materializes remote state +``` + +**PowerShell (requires `git` only):** + +```powershell +.\sync-mesh.ps1 # default: reads mesh.json +.\sync-mesh.ps1 -MeshJson custom.json # custom config path +``` + +Both scripts read `mesh.json`, pull from remote-trusted repos, curl from remote-opaque URLs, and materialize everything into `.mesh/remotes/`. + +--- + +## Getting Started + +### Prerequisites + +- Git (with SSH or HTTPS auth configured) +- A shell (bash/zsh) or PowerShell +- `jq` ([github.com/jqlang/jq](https://github.com/jqlang/jq)) for the bash sync script (PowerShell script has no external dependencies) + +### 1. Create the Mesh State Repo + +The **mesh state repo** is a shared git repository where squads publish their current state. Nothing more — no code, no automation, no agents. + +```bash +git clone git@github.com:our-org/squad-mesh-state.git +cd squad-mesh-state +``` + +### 2. Directory Structure + +One directory per squad, each with a `SUMMARY.md`: + +``` +squad-mesh-state/ +├── README.md # What this repo is, who participates +├── auth-squad/ +│ └── SUMMARY.md # Auth squad's current state +├── ci-squad/ +│ └── SUMMARY.md # CI squad's current state +└── data-squad/ + └── SUMMARY.md # Data squad's current state +``` + +### 3. Register Your Squad + +Create your directory, write initial state, push: + +```bash +mkdir my-squad +echo "# my-squad — active" > my-squad/SUMMARY.md +git add . && git commit -m "register my-squad" && git push +``` + +### 4. Configure `mesh.json` + +Point at the shared repo: + +```json +{ + "squads": { + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/squad-mesh-state.git", + "sync_to": ".mesh/remotes/ci-squad" + } + } +} +``` + +### 5. Run Your First Sync + +```bash +./sync-mesh.sh # reads mesh.json, materializes remote state +ls .mesh/remotes/ # should show directories per remote squad +``` + +> **Does the mesh state repo need its own Squad?** No. It's a shared data directory — a dumb pipe. No agents, no `.squad/` folder, no automation. Each squad pushes its own state via write partitioning. The repo is just a git-based rendezvous point. If you later want a "mesh observer" that monitors all squads, THAT would be its own Squad project — but it's not required and shouldn't be the state repo itself. + +--- + +## Cross-Org Setup (Zone 3) + +Remote org publishes `SUMMARY.md` at a URL. Add an HTTP entry to `mesh.json`: + +```json +"partner-squad": { + "zone": "remote-opaque", + "source": "https://partner.dev/squad-contracts/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-squad" +} +``` + +--- + +## How This Relates to Other Features + +### SubSquads (Streams) + +**SubSquads** partition work **within a single repo** using GitHub labels (e.g., `team:ui`, `team:backend`). Each SubSquad runs in its own Codespace but shares the same git repository. + +**Distributed mesh** coordinates **across repos and machines** — different organizations, different git repos, potentially no shared authentication. + +SubSquads solve "one repo, many teams." Distributed mesh solves "many repos, many machines, crossing org boundaries." + +See [SubSquads](./streams.md) for within-repo partitioning. + +### Export & Import + +**Export/import** is a **snapshot-based** knowledge transfer. You export a trained squad from one repo and import it into another. It's a one-time copy. + +**Distributed mesh** is **continuous coordination**. Remote squads keep working; you sync their latest state every time your agents wake up. + +Use export/import when you want to **clone a team**. Use distributed mesh when you want **live coordination**. + +See [Multiple Squads scenario](../scenarios/multiple-squads.md) for when to use each approach. + +--- + +## Upstream inheritance + +The **upstream module** and the **distributed mesh** serve different coordination needs. They're complementary, not competing. + +### Upstream: top-down inheritance + +The `upstream/` module (configured in `upstream.json`) is for **hierarchical inheritance**. An organization-level or team-level squad pushes skills, decisions, wisdom, casting policy, and routing rules **down** to project squads. The consuming squad treats upstream content as **read-only** — it inherits conventions but doesn't write back. + +### Mesh: peer coordination + +The distributed mesh (configured in `mesh.json`) is for **peer-to-peer coordination**. Squads on equal footing share their **current state** with each other. Each squad **publishes** its own state (SUMMARY.md, billboards) and **reads** everyone else's. It's read-write for each squad's own directory. + +### Use them together + +A squad can have **both** an upstream (inheriting org conventions) **and** mesh peers (coordinating with sibling squads). For example: + +- Your project squad inherits security policies and routing rules from the org-level squad via `upstream.json` +- The same squad coordinates with other project squads (auth, ci, data) via `mesh.json` + +### Comparison + +| | Upstream | Mesh | +|---|---|---| +| **Direction** | Top-down (parent → child) | Peer-to-peer (squad ↔ squad) | +| **Write model** | Read-only for consumer | Read-write (own directory) | +| **What flows** | Skills, decisions, wisdom, casting, routing | Current state (SUMMARY.md, billboards) | +| **Config file** | `upstream.json` | `mesh.json` | +| **Transport** | Local path / git clone / export JSON | Local path / git pull / HTTP curl | +| **Use case** | Org policies flowing into team projects | Sibling squads keeping each other informed | + +### What neither does + +Neither upstream nor mesh is about **agent-to-agent communication within a single squad**. That's the drop-box pattern — agents write to `decisions/inbox/`, read from `history.md`, and coordinate asynchronously within one `.squad/` directory. + +--- + +## What We're NOT Building + +- ❌ Federation protocol (git push/pull IS federation) +- ❌ Discovery service (mesh.json IS discovery) +- ❌ Auth system (git auth IS the auth system) +- ❌ A2A endpoints (no running servers) +- ❌ Schema versioning (markdown; LLM reads it) +- ❌ Real-time sync (agents are async; eventual consistency is correct) +- ❌ Message queues (agents aren't persistent; nobody's listening) +- ❌ CRDTs/conflict resolution (write partitioning; no conflicts possible) + +--- + +## Sample Prompts + +``` +configure a distributed mesh with our CI squad on GitHub +``` + +Creates a `mesh.json` entry for a remote-trusted squad and runs the first sync. + +``` +sync remote squad state before starting work +``` + +Runs the sync script to materialize the latest state from all configured remote squads. + +``` +add a partner squad from https://partner.dev/squad-contracts/SUMMARY.md +``` + +Adds a remote-opaque Zone 3 entry to `mesh.json` for cross-org coordination. + +``` +show me what remote squads are configured +``` + +Lists all squads in `mesh.json` and their zones. diff --git a/docs/src/content/docs/features/enterprise-platforms.md b/docs/src/content/docs/features/enterprise-platforms.md new file mode 100644 index 000000000..ca51877ae --- /dev/null +++ b/docs/src/content/docs/features/enterprise-platforms.md @@ -0,0 +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 ... +``` 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 72% rename from docs/features/human-team-members.md rename to docs/src/content/docs/features/human-team-members.md index ed2de7616..e6ce15798 100644 --- a/docs/features/human-team-members.md +++ b/docs/src/content/docs/features/human-team-members.md @@ -77,6 +77,24 @@ Their entry moves to `.squad/agents/_alumni/`. They can be re-added later. --- +## When to add a human member + +Not every collaborator needs a roster entry. Use this table to decide: + +| Scenario | Add to roster? | Why | +|----------|---------------|-----| +| Approves architecture decisions before implementation | ✅ Yes | Decision gate — agents route and wait | +| Reviews all docs PRs as a standing reviewer | ✅ Yes | Recurring review gate | +| Makes the final ship/no-ship call | ✅ Yes | Approval gate | +| Occasionally reviews PRs when tagged | ❌ No | Use @mention on the PR instead | +| Files issues and contributes code | ❌ No | Normal GitHub collaboration | + +**Litmus test:** If you want agents to *stop and wait* for someone's input before proceeding, add them. If they review asynchronously through normal GitHub flows, a roster entry adds no value. + +**You don't need to add yourself.** Squad reads `git config user.name` every session, so the team always knows who's driving. Adding yourself to the roster is optional — it formalizes routing and review tracking but isn't required for day-to-day interaction. + +--- + ## Tips - Use human members for approval gates — design review, compliance, final sign-off. 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/src/content/docs/features/squad-rc.md b/docs/src/content/docs/features/squad-rc.md new file mode 100644 index 000000000..998d0803c --- /dev/null +++ b/docs/src/content/docs/features/squad-rc.md @@ -0,0 +1,478 @@ +# squad rc + +> **Full remote control of GitHub Copilot from any device.** ACP passthrough mode for complete Copilot CLI access via secure tunnel. + +--- + +## What It Does + +`squad rc` (remote control) exposes GitHub Copilot CLI over a secure WebSocket tunnel, letting you chat with Copilot from your phone, tablet, or any browser. Unlike `squad start` (which mirrors terminal output), `squad rc` uses **ACP passthrough** — raw JSON-RPC communication directly with Copilot's Agent Communication Protocol. You get full Copilot capabilities, not just terminal visibility. + +```bash +squad rc --tunnel +# → QR code appears +# → Scan with phone +# → Chat with Copilot in browser (full capabilities) +``` + +--- + +## How It Differs from `squad start` + +| Feature | `squad rc` | `squad start` | +|--------------------------|-------------------------------------|----------------------------------| +| **Mode** | ACP passthrough (JSON-RPC) | PTY mirror (terminal streaming) | +| **Protocol** | Agent Communication Protocol (ACP) | xterm.js terminal emulation | +| **Access** | Full Copilot capabilities | Terminal output only | +| **Use Case** | Remote Copilot control | Demo/pair on terminal sessions | +| **Input** | Chat messages → Copilot stdin | Keyboard input → PTY | +| **Output** | Copilot responses → WebSocket | Terminal ANSI → WebSocket | +| **Mobile Optimized** | Yes (PWA, QR code, chat UI) | Yes (xterm.js, keyboard overlay) | +| **Startup Time** | ~15-20s (MCP server loading) | Immediate | +| **Team Roster** | Loaded from `.squad/team.md` | Not applicable | + +**When to use `squad rc`:** You want to control Copilot remotely (ask questions, run commands, access full agent capabilities). + +**When to use `squad start`:** You want to mirror a terminal session to your phone (demos, pairing, watching long-running processes). + +> 💡 **Looking for terminal mirroring?** See [squad start](./remote-control.md). + +--- + +## Prerequisites + +### Required + +- **GitHub Copilot CLI** — Install with: + ```bash + npm install -g @github/copilot + ``` + Verify with: `copilot --version` (v0.0.420+ recommended) + +- **devtunnel CLI** (for `--tunnel` mode) + ```bash + # Windows + winget install Microsoft.devtunnel + + # macOS + brew install devtunnel + + # Linux + # Download from https://aka.ms/devtunnels/download + ``` + +### Setup + +1. **Authenticate devtunnel** + ```bash + devtunnel user login + ``` + Sign in with your Microsoft or GitHub account. + +2. **Verify Copilot CLI** + ```bash + copilot --version + ``` + Should return `0.0.420` or higher. + +--- + +## Quick Start + +**Local testing (no tunnel):** +```bash +squad rc +# → Prints: Bridge running on port 3000 +# → Open http://localhost:3000 +``` + +**Remote access (with tunnel):** +```bash +squad rc --tunnel +# → Creates devtunnel +# → Shows QR code +# → Scan with phone or copy URL +``` + +**Custom port:** +```bash +squad rc --port 8080 +``` + +**Different directory:** +```bash +squad rc --path ~/my-project --tunnel +``` + +--- + +## All Flags & Options + +| Flag | Description | Default | +|---------------------|--------------------------------------------------|----------------------| +| `--tunnel` | Create a devtunnel for remote access | `false` (local only) | +| `--port ` | HTTP server port | `0` (random) | +| `--path ` | Working directory for Copilot | Current directory | + +**Example:** +```bash +# Local access on port 5000 +squad rc --port 5000 + +# Remote tunnel from specific project +squad rc --tunnel --path ~/repos/my-app +``` + +--- + +## How It Works + +### Architecture Diagram + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Remote Browser (PWA) │ +│ • QR code scan │ +│ • Chat UI │ +│ • Keyboard shortcuts │ +│ • Replay buffer │ +└──────────────────┬──────────────────────────────────────────┘ + │ + │ WebSocket (session token auth) + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ RemoteBridge (squad-sdk) │ +│ • HTTP server (serves PWA) │ +│ • WebSocket server (broadcasts messages) │ +│ • Session token + ticket auth │ +│ • Rate limiting (30 req/min per IP) │ +│ • Connection limits (5 per IP) │ +│ • CSP headers │ +│ • Audit logging │ +└──────────────────┬──────────────────────────────────────────┘ + │ + │ ACP passthrough (raw JSON-RPC) + │ • Client message → Copilot stdin + │ • Copilot stdout → Broadcast to clients + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Copilot CLI (--acp mode) │ +│ • Spawned as child process │ +│ • stdio: ['pipe', 'pipe', 'pipe'] │ +│ • MCP servers load (~15-20s warmup) │ +│ • Processes ACP JSON-RPC messages │ +└─────────────────────────────────────────────────────────────┘ + │ + │ File system, Git, tools + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Your Repository │ +│ • Copilot reads .squad/team.md (optional) │ +│ • Full file system access in working directory │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Message Flow + +**Outbound (Remote → Copilot):** +1. User types message in browser +2. WebSocket sends JSON payload: `{ type: 'prompt', text: '...' }` +3. RemoteBridge writes to Copilot stdin: `\n` +4. Copilot processes request + +**Inbound (Copilot → Remote):** +1. Copilot writes JSON-RPC to stdout +2. RemoteBridge reads line from Copilot stdout +3. RemoteBridge broadcasts to all WebSocket clients +4. Browser renders Copilot response + +### Team Roster Loading + +If `.squad/team.md` exists, `squad rc` parses the Active members table: + +```markdown +| Name | Role | Status | +|-----------|---------------|--------| +| Fenster | Core Dev | Active | +| Edie | TypeScript | Active | +``` + +Agents appear in the `/agents` command and are available for direct messages (`@Fenster ...`). + +### Connection Monitoring + +Every 5 seconds, the bridge logs connected client count: +``` +● 2 client(s) connected +``` + +--- + +## Security Model + +`squad rc` implements 7 layers of security: + +### 1. Session Token Authentication +- **What:** UUID session token generated on bridge startup +- **Where:** `RemoteBridge` constructor (line 47 in `bridge.ts`) +- **How:** All API routes check `Authorization: Bearer ` header or `?token=` query param +- **Enforcement:** Line 123-128 in `bridge.ts` + +### 2. One-Time Ticket System +- **What:** Exchange session token for single-use WebSocket ticket +- **Where:** `/api/auth/ticket` endpoint (line 112-120 in `bridge.ts`) +- **Why:** Session token can't be observed in WebSocket URL logs +- **TTL:** 60 seconds, consumed on first use +- **Cleanup:** Expired tickets garbage-collected every 30s (line 51-56 in `bridge.ts`) + +### 3. Rate Limiting +- **HTTP:** 30 requests/minute per IP (line 97-107 in `bridge.ts`) +- **WebSocket:** 20 messages/minute per connection (enforced in `handleMessage`) +- **Penalty:** 429 Too Many Requests (HTTP) or connection close (WebSocket) + +### 4. Secret Redaction +- **What:** Environment variable patterns redacted from messages +- **Patterns:** `API_KEY=*`, `TOKEN=*`, `PASSWORD=*`, `SECRET=*` +- **Applied:** Before broadcast to clients (message content sanitized) + +### 5. Connection Limits +- **Per IP:** 5 concurrent WebSocket connections +- **Global:** Enforced via `ipConnections` map in `RemoteBridge` +- **Rejection:** Connection denied in `verifyClient` callback + +### 6. Content Security Policy Headers +- **Headers:** `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`, `Strict-Transport-Security: max-age=31536000`, `Cache-Control: no-store` +- **Where:** Line 156-161 in `rc.ts` (static file handler) +- **Effect:** Prevents clickjacking, MIME sniffing, referrer leaks + +### 7. Devtunnel Private Auth +- **What:** Tunnel is private by default (only your MS/GitHub account can connect) +- **Where:** `devtunnel create` command (line 47-58 in `rc-tunnel.ts`) +- **Labels:** Tunnel tagged with `squad`, `repo`, `branch`, `machine` labels +- **Expiry:** 24 hours (line 48 in `rc-tunnel.ts`) + +### Session Expiry +- **TTL:** 4 hours from bridge startup +- **Check:** Every 60 seconds (line 60-67 in `bridge.ts`) +- **Enforcement:** New connections rejected, existing connections closed + +--- + +## Built-in Commands + +Type these in the PWA chat: + +### `/status` +Shows current bridge state: +``` +Squad RC | Repo: squad-pr | Branch: main | Agents: 5 | Copilot: passthrough | Connections: 2 +``` + +### `/agents` +Lists all agents from `.squad/team.md`: +``` +Team Roster: +• Fenster (Core Dev) +• Edie (TypeScript Engineer) +• McManus (DevRel) +• Rabin (Distribution) +• Keaton (PM) +``` + +### `@agentName ` +Direct message to a specific agent: +``` +@Edie Can you review the TypeScript types in src/index.ts? +``` +Routed to the named agent if supported by your squad configuration. + +--- + +## Mobile Experience + +### QR Code +When `--tunnel` is enabled, a QR code is printed to the terminal. Scan with your phone's camera to open the remote control URL instantly. + +### Keyboard Shortcuts +- **Enter:** Send message +- **Shift+Enter:** New line in message +- **Cmd/Ctrl+K:** Clear chat history (client-side) +- **Cmd/Ctrl+R:** Reconnect WebSocket + +### Replay Buffer +All messages are stored in the bridge's replay buffer (default: 500 messages). New connections automatically receive full conversation history on connect. + +### Progressive Web App (PWA) +The remote UI is a PWA with: +- **Offline support:** Service worker caches UI assets +- **Install prompt:** Add to Home Screen on iOS/Android +- **Responsive layout:** Mobile-first design, adapts to desktop + +--- + +## Audit Logging + +### Log Location +``` +~/.cli-tunnel/audit/squad-audit-.jsonl +``` + +### What's Logged +- WebSocket connections/disconnections +- All prompts (user input) +- All agent responses +- Tool calls +- Permission requests +- Errors + +### Log Format +JSONL (JSON Lines) — one event per line: +```json +{"timestamp":"2026-03-13T10:15:00Z","type":"connection","clientId":"abc123","ip":"192.168.1.5"} +{"timestamp":"2026-03-13T10:15:10Z","type":"prompt","clientId":"abc123","text":"What's the latest commit?"} +{"timestamp":"2026-03-13T10:15:12Z","type":"response","agentName":"Copilot","content":"The latest commit is..."} +``` + +### Accessing Logs +```bash +# View live logs +tail -f ~/.cli-tunnel/audit/squad-audit-*.jsonl + +# Search for prompts +grep '"type":"prompt"' ~/.cli-tunnel/audit/squad-audit-*.jsonl | jq . +``` + +--- + +## Troubleshooting + +### `Copilot not available` error + +**Symptom:** +``` +⚠ Copilot not available: spawn copilot ENOENT +``` + +**Cause:** Copilot CLI not installed or not in PATH. + +**Fix:** +```bash +npm install -g @github/copilot +``` + +--- + +### `devtunnel CLI not found` + +**Symptom:** +``` +⚠ devtunnel CLI not found. Install with: + winget install Microsoft.devtunnel +``` + +**Cause:** `devtunnel` binary not in PATH. + +**Fix:** +- **Windows:** `winget install Microsoft.devtunnel` +- **macOS:** `brew install devtunnel` +- **Linux:** Download from https://aka.ms/devtunnels/download + +--- + +### `Tunnel failed: devtunnel host exited with code 1` + +**Symptom:** +``` +⚠ Tunnel failed: devtunnel host exited with code 1 + Running in local-only mode. +``` + +**Cause:** Not authenticated with devtunnel. + +**Fix:** +```bash +devtunnel user login +``` +Sign in with your Microsoft or GitHub account, then retry. + +--- + +### WebSocket connection refused + +**Symptom:** Browser console shows `WebSocket connection to 'wss://...' failed: Error during WebSocket handshake` + +**Cause:** Session token mismatch or session expired. + +**Fix:** +1. **Refresh the QR code:** Stop `squad rc` (Ctrl+C) and restart +2. **Check expiry:** Sessions expire after 4 hours. Restart the bridge. +3. **Verify token:** Ensure you're using the URL from the QR code exactly as printed. + +--- + +### Copilot responses are slow or not appearing + +**Symptom:** You send a message but see no response for 20+ seconds. + +**Cause:** Copilot's MCP servers are still loading (first 15-20s after `squad rc` starts). + +**Expected behavior:** +``` +Spawning copilot --acp (MCP servers loading ~15-20s)... +✓ Copilot ACP passthrough active +``` + +**Fix:** Wait ~20 seconds after seeing the "Spawning copilot" message. Copilot is loading its Model Context Protocol servers (GitHub, Bing, etc.) and won't respond until ready. + +--- + +### `[Copilot passthrough not active] Echo: ...` + +**Symptom:** Responses are prefixed with `[Copilot passthrough not active]`. + +**Cause:** Copilot CLI failed to spawn (binary missing, unsupported OS, or crashed). + +**Fix:** +1. Verify Copilot CLI: `copilot --version` +2. Check logs for "Spawning copilot" errors +3. On Windows, ensure `copilot.exe` is at `C:\ProgramData\global-npm\node_modules\@github\copilot\node_modules\@github\copilot-win32-x64\copilot.exe` (line 185-189 in `rc.ts` for hardcoded fallback) + +--- + +### Port already in use + +**Symptom:** +``` +Error: listen EADDRINUSE: address already in use 127.0.0.1:3000 +``` + +**Cause:** Another process is using the default port. + +**Fix:** +```bash +squad rc --port 0 # Auto-assign free port +# OR +squad rc --port 8080 # Specific port +``` + +--- + +### Can't connect from mobile (tunnel URL works on desktop) + +**Symptom:** Desktop browser connects fine, mobile shows "Connection refused" or "Unauthorized". + +**Cause 1:** Tunnel auth requires same Microsoft/GitHub account on mobile. +**Fix:** Sign in to your MS/GitHub account in your mobile browser, then open the tunnel URL. + +**Cause 2:** Tunnel expired (24-hour TTL). +**Fix:** Restart `squad rc --tunnel` to create a new tunnel. + +--- + +## See Also + +- [squad start](./remote-control.md) — PTY mirror mode for terminal streaming +- [CLI Reference](../reference/cli.md) — All squad commands +- [Remote Control Protocol](https://github.com/bradygaster/squad/blob/main/packages/squad-sdk/src/remote/protocol.ts) — Wire protocol types +- [RemoteBridge SDK](https://github.com/bradygaster/squad/blob/main/packages/squad-sdk/src/remote/bridge.ts) — Server implementation +- [devtunnel documentation](https://aka.ms/devtunnels) — Tunnel setup and auth diff --git a/docs/features/streams.md b/docs/src/content/docs/features/streams.md similarity index 55% rename from docs/features/streams.md rename to docs/src/content/docs/features/streams.md index 1b7185199..0b2cf6b46 100644 --- a/docs/features/streams.md +++ b/docs/src/content/docs/features/streams.md @@ -1,146 +1,148 @@ -# Squad Workstreams - -> Scale Squad across multiple Codespaces by partitioning work into labeled workstreams. - -## What Are Workstreams? - -A **workstream** is a named partition of work within a Squad project. Each workstream 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 workstream, enabling parallel work across teams. - -## Why Workstreams? - -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 - -Workstreams solve this by giving each Codespace a scoped view of the project. - -## Configuration - -### 1. Create `.squad/workstreams.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 Workstream - -There are three ways to tell Squad which workstream 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 workstreams activate ui-team -``` - -This writes a `.squad-workstream` file (gitignored) so the setting is local to your machine. - -#### Auto-select (single workstream) - -If `workstreams.json` contains only one workstream, it's automatically selected. - -### 3. Resolution Priority - -1. `SQUAD_TEAM` env var (highest) -2. `.squad-workstream` file -3. Single-workstream auto-select -4. No workstream (classic single-squad mode) - -## Workstream Definition Fields - -| Field | Required | Description | -|-------|----------|-------------| -| `name` | Yes | Unique workstream identifier (kebab-case) | -| `labelFilter` | Yes | GitHub label to filter issues | -| `folderScope` | No | Directories this workstream may modify | -| `workflow` | No | `branch-per-issue` (default) or `direct` | -| `description` | No | Human-readable purpose | - -## CLI Reference - -```bash -# List configured workstreams -squad workstreams list - -# Show workstream activity (branches, PRs) -squad workstreams status - -# Activate a workstream locally -squad workstreams activate -``` - -## How It Works - -### Triage (Ralph) - -When a workstream is active, Ralph's triage only picks up issues labeled with the workstream's `labelFilter`. Unmatched issues are left for other workstreams 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 workstreams). - -### 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 workstreams editing the same file won't conflict until merge time. - -> **Tip:** If two workstreams' 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-Workstream - -You don't need a separate Codespace per workstream. One machine can serve multiple workstreams: - -```bash -# Switch between workstreams manually -squad workstreams activate ui-team # Ralph works team:ui issues -# ... later ... -squad workstreams 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 64% rename from docs/features/vscode.md rename to docs/src/content/docs/features/vscode.md index fff5b8ef0..b928e854b 100644 --- a/docs/features/vscode.md +++ b/docs/src/content/docs/features/vscode.md @@ -16,7 +16,7 @@ This guide covers what's different, what's the same, and when to use CLI vs VS C - **VS Code** — Latest version - **GitHub Copilot extension** — `GitHub.copilot` (installed, authenticated) - **Workspace trust** — Your workspace must be trusted (VS Code security) -- **Node.js 22+** — If running CLI to initialize Squad +- **Node.js 20+ (LTS)** — If running CLI to initialize Squad - **Squad installed** — Either in the repo already (from CLI), or initialized fresh via agent selection ### Initial Setup @@ -112,9 +112,101 @@ See [Getting Started](../get-started/first-session.md) for your first VS Code se --- +## Extension Developer Guide + +If you're building a VS Code extension that integrates with Squad, follow these patterns. + +### Detect Client Mode + +```typescript +const isVSCodeMode = process.env.SQUAD_CLIENT === 'vscode'; + +if (!isVSCodeMode) { + console.warn('SquadUI should only run in VS Code'); + return; +} +``` + +### 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 — this will call `process.exit()` and crash your extension. + +### Load Configuration + +```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) { + console.warn('Squad not found:', err.message); + return; +} +``` + +### Spawn Agents + +```typescript +import { SquadCoordinator } from '@bradygaster/squad-sdk'; + +const coordinator = new SquadCoordinator({ teamRoot: squadPath }); +await coordinator.initialize(); + +const decision = await coordinator.route('refactor this function'); +await coordinator.execute(decision, 'refactor this function'); +``` + +### Stream Responses + +```typescript +import { startStreaming } from '@bradygaster/squad-sdk'; + +const stream = await startStreaming(agentResponse); +for await (const chunk of stream) { + vscodePanel.append(chunk); +} +``` + +### Handle Errors Gracefully + +```typescript +try { + const result = await coordinator.route(userTask); +} catch (err) { + vscode.window.showErrorMessage(`Squad error: ${err.message}`); +} +``` + +Never call `process.exit()` in an extension — it crashes VS Code. + +### Pass Editor Context + +```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, +}); +``` + +--- + ## See Also - [Getting Started](../get-started/installation.md) — Installation and setup guide - [Parallel Execution](parallel-execution.md) — How Squadron fan-outs agents - [Model Selection](model-selection.md) — Cost-first routing strategy -- [CLI Shell Commands](../cli/shell.md) — Shell commands and features +- [Interactive Shell](../guide/shell.md) — Shell commands and features +- [SDK API Reference](../reference/api-reference.md) — Full SDK type and function reference 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/src/content/docs/get-started/choosing-your-path.md b/docs/src/content/docs/get-started/choosing-your-path.md new file mode 100644 index 000000000..16eacec5e --- /dev/null +++ b/docs/src/content/docs/get-started/choosing-your-path.md @@ -0,0 +1,82 @@ +# Choose your path + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +CLI, Copilot agent, or SDK? Pick the right mode for your workflow. + +--- + +## Three modes + +### CLI mode + +Install Squad globally or per-project, then use terminal commands to initialize, route work, and manage your team. + +```bash +npm install -g @bradygaster/squad-cli +squad init +squad status +squad watch +``` + +**Use for:** Terminal workflows, automation scripts, CI/CD integration. + +--- + +### Copilot agent mode + +Talk to Squad in GitHub Copilot CLI or VS Code. Squad is built-in as an agent. Your `.squad/` directory works identically to CLI mode. + +```bash +copilot +> /agent Squad + +Squad: Hey Brady, what are you building? +``` + +**Use for:** Conversational workflows, exploratory work, VS Code users. + +--- + +### SDK mode + +Write TypeScript code that spawns agents, routes work, and coordinates teams programmatically. Full access to Squad's internals. + +```bash +npm install @bradygaster/squad-sdk +``` + +```typescript +import { Coordinator } from '@bradygaster/squad-sdk'; + +const coordinator = new Coordinator(); +const result = await coordinator.route('Build a login page'); +``` + +**Use for:** Building tools on Squad, custom integrations, advanced automation. + +--- + +## Decision table + +| **Your goal** | **Use** | +|---------------|---------| +| Try Squad quickly | **Copilot agent** — no install | +| Work in the terminal | **CLI** | +| Work in VS Code | **Copilot agent** | +| Automate repetitive tasks | **CLI** or **SDK** | +| Build custom tooling | **SDK** | +| CI/CD integration | **CLI** or **SDK** | + +--- + +## Can I use multiple modes? + +Yes. Your `.squad/` directory is the source of truth. CLI, Copilot agent, and SDK all read and write the same files. You can switch between modes anytime. + +Example workflow: +1. Use **Copilot agent** to form your team and do exploratory work +2. Use **CLI** (`squad watch`) to monitor issues in the background +3. Use **SDK** to build a custom deployment script that spawns agents + +All three modes share the same memory and decisions. diff --git a/docs/get-started/first-session.md b/docs/src/content/docs/get-started/first-session.md similarity index 81% rename from docs/get-started/first-session.md rename to docs/src/content/docs/get-started/first-session.md index 769319432..6c62bbebc 100644 --- a/docs/get-started/first-session.md +++ b/docs/src/content/docs/get-started/first-session.md @@ -48,7 +48,7 @@ Start the Copilot CLI: copilot ``` -Select **Squad** from the `/agent` list (CLI) or `/agents` (VS Code). Squad greets you by name (pulled from `git config user.name`): +Select **Squad** from the `/agent` list (CLI) or `/agents` (VS Code). Squad greets you by name: ``` Hey Brady, what are you building? @@ -61,7 +61,7 @@ Describe your project: > post recipes, search by ingredient, and save favorites. ``` -Squad proposes a team. Names come from a fictional universe — the exact universe depends on your project shape and history: +Squad proposes a team. The coordinator analyzes your description and suggests specialists: ``` Here's your team: @@ -72,6 +72,8 @@ Here's your team: 🧪 Lambert — Tester Tests, quality, edge cases 📋 Scribe — (silent) Memory, decisions, session logs +**Scribe** and **Ralph** are always on every roster — you don't manage them. + Look right? Say yes, add someone, or change a role. (Or just give me a task to start!) ``` @@ -86,7 +88,26 @@ Say "yes" or skip straight to a task (which is implicit confirmation): > Yes. Dallas, set up the Express server with basic routing. ``` -Squad creates the `.squad/` directory structure — team roster, routing rules, casting state, ceremony config, agent charters, and histories — all seeded with your project context. Then it spawns Dallas: +Squad creates the `.squad/` directory structure — team roster, routing rules, casting state, ceremony config, agent charters, and histories — all seeded with your project context. Each agent spawns to do their work. + +### What's inside .squad/? + +| File/Directory | Purpose | +|---|---| +| `team.md` | Team roster, roles, and member info | +| `routing.md` | Work routing rules (which agent handles what) | +| `decisions.md` | Team decisions — all agents read this before working | +| `agents/` | Each agent's charter and history (their memory) | +| `ceremonies.md` | Ceremony schedule (retrospectives, reviews, etc.) | +| `casting/` | Team formation history and casting state | +| `skills/` | Reusable capabilities agents can learn | +| `templates/` | Format reference files for docs, PRDs, charters | + +**You own these files.** Edit them anytime — change roles, add routing rules, fix decisions. Squad reads them before every spawn. + +**Commit `.squad/` to version control.** It's your team's brain. Anyone who clones the repo gets the team with all their knowledge. + +Then it spawns Dallas: ``` 🔧 Dallas — setting up Express server with routing @@ -158,7 +179,7 @@ At any point, check status: > Where are we? ``` -This is a Direct mode response — no agent spawn, just the coordinator reading recent logs: +The coordinator reads recent logs: ``` Last session: Recipe listing page (15 minutes ago) @@ -255,7 +276,7 @@ squad export 5 agents, 3 skills, 6 decisions ``` -This snapshot contains everything — charters, histories, casting state, skills, and decisions. Import into another repo anytime: +This snapshot contains charters, histories, casting state, skills, and decisions. Import into another repo anytime: ```bash cd ../other-project @@ -267,8 +288,8 @@ squad import ../my-app/squad-export.json ## Tips -- **First session is the slowest.** Agents have no history yet. After 2–3 sessions, they know your conventions and stop asking repeated questions. -- **Commit `.squad/`.** It's your team's brain. Anyone who clones the repo gets the team with all their knowledge. +- **First session is slowest.** Agents have no history yet. After 2–3 sessions, they know your conventions. +- **Commit `.squad/`** — your team's brain. Anyone who clones the repo gets the full team. - **Say "team" for big tasks.** The word "team" triggers parallel fan-out across multiple agents. - **Name an agent for focused work.** `"Dallas, fix the login bug"` sends work to one specific agent. - **Directives are sticky.** Once captured, they persist across all future sessions. diff --git a/docs/src/content/docs/get-started/five-minute-start.md b/docs/src/content/docs/get-started/five-minute-start.md new file mode 100644 index 000000000..29667ea95 --- /dev/null +++ b/docs/src/content/docs/get-started/five-minute-start.md @@ -0,0 +1,87 @@ +# Quick start + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +Your first 5 minutes with Squad. Prove it works before you learn anything. + +--- + +## Prerequisites + +- **Node.js 20+** — Check with `node --version` +- **Git repository** — New or existing + +--- + +## Install + +```bash +npm install --save-dev @bradygaster/squad-cli +``` + +Then initialize: + +```bash +npx squad init +``` + +You'll see: + +``` +✅ Squad installed. + .github/agents/squad.agent.md — coordinator agent + .squad/templates/ — 11 template files + +Open GitHub Copilot and select Squad from the agent list. +``` + +--- + +## Validate + +Check that Squad created your team directory: + +```bash +ls .squad/ +``` + +You should see: `team.md`, `routing.md`, `decisions.md`, `agents/`, and more. + +Confirm Squad is ready: + +```bash +npx squad status +``` + +--- + +## Try it + +Open GitHub Copilot in your terminal or VS Code. Select **Squad** from the agent list (`/agent Squad` in CLI or `/agents` in VS Code). + +Say something simple: + +``` +> I'm building a task management app with React and Node.js. +> Users can create, update, and delete tasks. +``` + +Squad forms your team and responds with agent names and roles. Say yes, or just give your first task: + +``` +> Team, create a basic Express server with a /health endpoint. +``` + +Squad spawns agents and does the work. + +--- + +## What just happened? + +Squad read your description, formed a team of specialists, wrote their charters to `.squad/agents/`, and coordinated parallel work. Check `.squad/decisions.md` to see what they decided. + +--- + +## Next steps + +[**Your first session**](first-session) — Step-by-step walkthrough of parallel work, decisions, and memory. diff --git a/docs/get-started/installation.md b/docs/src/content/docs/get-started/installation.md similarity index 79% rename from docs/get-started/installation.md rename to docs/src/content/docs/get-started/installation.md index e1c4fafaa..65d916532 100644 --- a/docs/get-started/installation.md +++ b/docs/src/content/docs/get-started/installation.md @@ -59,6 +59,21 @@ npm install -g @bradygaster/squad-cli@latest --- +## Which method should I use? + +Pick based on what you're doing: + +| **You want to...** | **Use** | **Why** | +|--------------------|---------|---------| +| Try Squad quickly | **CLI** with `npx` | No install needed. Run `npx @bradygaster/squad-cli init` and you're testing it. | +| Use Squad across all projects | **CLI** with `--global` | One install. Works everywhere. Run `squad` from any terminal. | +| Work inside VS Code | **VS Code** (just open your project) | Already using Copilot? Squad just works. Same `.squad/` directory as CLI. | +| Build tools on top of Squad | **SDK** | Typed APIs, routing config, agent lifecycle hooks. Programmatic access to everything. | + +Can't decide? → Start with **CLI**. You can always add VS Code or the SDK later. Your `.squad/` directory works identically everywhere. + +--- + ## 2. VS Code Squad works in VS Code through GitHub Copilot. Your `.squad/` directory works identically in both CLI and VS Code — same agents, same decisions, same memory. diff --git a/docs/get-started/migration.md b/docs/src/content/docs/get-started/migration.md similarity index 99% rename from docs/get-started/migration.md rename to docs/src/content/docs/get-started/migration.md index 11eecb5c3..d09459217 100644 --- a/docs/get-started/migration.md +++ b/docs/src/content/docs/get-started/migration.md @@ -522,7 +522,7 @@ npm install -g @bradygaster/squad-cli@0.8.17 - **TypeScript strict mode:** Full type safety across the SDK and CLI. - **Semver fix:** Version format now follows the semver spec (`0.8.18-preview.N` instead of `0.8.18.N-preview`). -For the full list of changes, see the [CHANGELOG](../CHANGELOG.md). +For the full list of changes, see the [CHANGELOG](https://github.com/bradygaster/squad/blob/main/CHANGELOG.md). --- diff --git a/docs/guide.md b/docs/src/content/docs/guide.md similarity index 99% rename from docs/guide.md rename to docs/src/content/docs/guide.md index c13fdb245..bd7842423 100644 --- a/docs/guide.md +++ b/docs/src/content/docs/guide.md @@ -28,7 +28,7 @@ npx github:bradygaster/squad ``` **Requirements:** -- Node.js 22+ +- Node.js 20+ (LTS) - GitHub Copilot (CLI, VS Code, Visual Studio, or Coding Agent) - A git repository (Squad stores team state in `.ai-team/`) - **`gh` CLI** — required for GitHub Issues, PRs, Ralph, and Project Boards ([install](https://cli.github.com/)) @@ -438,7 +438,7 @@ The coordinator uses 6.6% of its window. A 12-week veteran agent uses 4.5% — b - **Experimental** — file formats and APIs may change between versions. - **Silent success bug** — approximately 7–10% of background agent spawns complete all their file writes but return no text response. This is a platform-level issue. Squad detects it by checking the filesystem for work product and reports what it finds. Work is not lost. - **Platform latency** — response times depend on the Copilot platform. Complex multi-agent tasks take 40–60 seconds. Simple questions are answered in 2–3 seconds. -- **Node 22+** — requires Node.js 22.0.0 or later. +- **Node 20+** — requires a Node.js LTS release (v20.0.0 or later). - **GitHub Copilot required** — Squad works across Copilot hosts (CLI, VS Code, Visual Studio, Coding Agent). - **First session is the least capable** — agents improve as they accumulate history. Give it a few sessions before judging. diff --git a/docs/src/content/docs/guide/contributing.md b/docs/src/content/docs/guide/contributing.md new file mode 100644 index 000000000..251d04c8d --- /dev/null +++ b/docs/src/content/docs/guide/contributing.md @@ -0,0 +1,311 @@ +# Contributing to Squad + +Squad is an open-source project built by contributors who believe in democratizing multi-agent development. Whether you're fixing a bug, adding a feature, or improving documentation, your work helps the entire community. + +This guide covers everything you need to know: from setting up your local environment to opening a pull request. + +## Prerequisites + +Before contributing, ensure you have: + +- **Node.js** ≥20.0.0 +- **npm** ≥10.0.0 (for workspace support) +- **Git** with SSH agent (for package resolution) +- **gh CLI** (for GitHub integration testing) + +## Monorepo Structure + +Squad is an npm workspace monorepo with two packages: + +``` +squad/ +├── packages/squad-cli/ # CLI tool (@bradygaster/squad-cli) +├── packages/squad-sdk/ # Runtime SDK (@bradygaster/squad-sdk) +├── src/ # Legacy CLI code (migrating to packages/) +├── dist/ # Compiled output +├── .squad/ # Team state and agent history +├── docs/ # Documentation and proposals +└── test-fixtures/ # Test data +``` + +### Package Independence + +- **squad-sdk**: Core runtime, agent orchestration, tool registry. No CLI dependencies. +- **squad-cli**: Command-line interface. Depends on squad-sdk. + +Each package has independent versioning via changesets. A change to squad-sdk may bump only squad-sdk; a change to CLI bumps only squad-cli. + +## Getting Started + +### 1. Clone and Install + +**Step 1: Fork the repo on GitHub** + +Go to [github.com/bradygaster/squad](https://github.com/bradygaster/squad) and click "Fork" to create your own copy. + +**Step 2: Clone your fork** + +```bash +git clone git@github.com:{yourusername}/squad.git +cd squad +``` + +**Step 3: Add upstream remote** + +```bash +git remote add upstream git@github.com:bradygaster/squad.git +``` + +**Step 4: Fetch the dev branch** + +```bash +git fetch upstream dev +``` + +**Step 5: Install dependencies** + +```bash +npm install +``` + +npm workspaces automatically links local packages. `@bradygaster/squad-cli` can import from `@bradygaster/squad-sdk` without publishing. + +### 2. Build + +```bash +# Compile TypeScript to dist/ +npm run build + +# Build + bundle CLI (includes esbuild) +npm run build:cli + +# Watch mode (auto-recompile on changes) +npm run dev +``` + +### 3. Test + +```bash +# Run all tests (Vitest) +npm test + +# Watch mode +npm run test:watch +``` + +### 4. Lint + +```bash +# Type check only (no emit) +npm run lint +``` + +### 5. Keeping Your Fork in Sync + +Before opening or updating a PR, rebase your branch on the latest upstream dev: + +```bash +git fetch upstream +git rebase upstream/dev +git push origin your-branch --force-with-lease +``` + +Always rebase before opening or updating a PR to ensure your changes are based on the latest integration branch. + +## Development Workflow + +### Creating a Feature Branch + +Follow the branch naming convention from `.squad/decisions.md`: + +```bash +# For user-facing work, use user_name/issue-number-slug format +git checkout -b bradygaster/217-readme-help-update +# or +git checkout -b keaton/210-resolution-api + +# For team-internal work, use agent_name/issue-number-slug +git checkout -b mcmanus/documentation +git checkout -b edie/refactor-router +``` + +### Before Committing + +1. **Compile:** `npm run build` (or `npm run dev` watch mode) +2. **Test:** `npm test` +3. **Type check:** `npm run lint` + +All checks must pass before commit. + +### Commit Message Format + +Keep messages clear and concise. Reference the issue number: + +``` +Brief description of change + +Longer explanation if needed. Reference #210, #217, etc. + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> +``` + +The Co-authored-by trailer is **required** for all commits (added by Copilot CLI). + +### Pull Request Process + +1. Add a changeset: `npx changeset add` (required before PR — see Changesets section) +2. Push your branch: `git push origin {yourusername}/217-readme-help-update` +3. Create a PR with explicit base and head: `gh pr create --base dev --repo bradygaster/squad --head {yourusername}:your-branch` +4. Link the issue: Add `Closes #217` to PR description +5. Wait for CI checks to pass +6. Request review from the team (agents will respond via comments) + +## Code Style & Conventions + +Squad follows strict TypeScript conventions: + +- **Type Safety:** `strict: true`, `noUncheckedIndexedAccess: true` +- **No `@ts-ignore`** — if a type error exists, fix the code +- **ESM-only** — no CommonJS, no dual-package +- **Async/await** — use async iterators for streaming +- **Error handling:** Structured errors with `fatal()`, `error()`, `warn()`, `info()` +- **No hype in docs** — factual, substantiated claims only (tone ceiling) + +## Documentation + +- **README.md** — User-facing guide, quick start, architecture overview +- **CONTRIBUTING.md** — Contributor guidelines (repo root) +- **docs/proposals/** — Design docs for significant changes (required before code) +- **.squad/agents/[name]/history.md** — Agent learnings and project context + +All docs in v1 are **internal only**. No public docs site until v2. + +## Local Development Versioning + +When developing Squad locally, set the package version to `{next-version}-preview`. For example, if the last published version is `0.8.5.1`, the local dev version should be `0.8.6-preview`. + +This convention makes `squad version` show the preview tag locally, clearly indicating you're running unreleased source code, not the published npm package. The release agent will bump this to the final version at publish time, then immediately back to the next preview version for continued development. + +### Making the `squad` Command Use Your Local Build + +To make the `squad` CLI command globally available and pointing to your local development build: + +```bash +npm run build -w packages/squad-sdk && npm run build -w packages/squad-cli +npm link -w packages/squad-cli +``` + +After this, `squad version` will show `0.8.6-preview` (or the current preview version). When you make code changes and rebuild, the `squad` command automatically picks up the changes—no need to reinstall. To verify your local build is active, the version output should include the `-preview` tag. + +To revert back to the globally installed npm package version, run: + +```bash +npm unlink -w packages/squad-cli +``` + +## Changesets: Independent Versioning + +Squad uses [@changesets/cli](https://github.com/changesets/changesets) for independent package versioning. + +### Adding a Changeset + +Before your PR is merged, add a changeset describing your changes: + +```bash +npx changeset add +``` + +This prompts: +1. Which packages changed? (squad-sdk, squad-cli, both) +2. What type? (patch, minor, major) +3. Brief summary of changes + +Creates a file in `.changeset/` that's merged with your PR. + +### Example Changeset + +```markdown +--- +"@bradygaster/squad-sdk": patch +"@bradygaster/squad-cli": patch +--- + +Update help text and README for npm distribution. Add squad status command to docs. +``` + +### Release Workflow + +The team runs changesets on the `main` branch (via GitHub Actions): + +```bash +npx changeset publish +``` + +This: +1. Bumps versions in `package.json` +2. Generates `CHANGELOG.md` entries +3. Publishes to npm +4. Creates GitHub releases + +You don't need to manually version — changesets handle it. + +## Branch Strategy + +- **main** — Stable, published releases. All merges include changesets. +- **insider** — Pre-release features, edge cases. Tag releases as `@insider`. +- **bradygaster/dev** — Integration branch. **All PRs from forks must target this branch**, not `main`. +- **user/issue-slug** — Feature branches from users or agents. + +## Continuous Integration + +GitHub Actions runs on every push: + +1. **Build:** `npm run build` and `npm run build:cli` +2. **Test:** `npm test` +3. **Lint:** `npm run lint` +4. **Changeset status:** `npm run changeset:check` (ensures PRs include a changeset) + +All checks must pass before merge. + +## Common Tasks + +### Add a CLI Command + +1. Create the command file in `src/cli/commands/[name].js` +2. Add the route in `src/index.ts` (the `main()` function) +3. Update help text in the `--help` handler +4. Add tests in `test/cli/commands/[name].test.ts` +5. Document in README.md + +### Add an SDK Export + +1. Implement the feature in `src/[module]/` +2. Export from `src/index.ts` +3. Add tests +4. Document in README.md SDK section + +### Migrate Legacy Code + +The `src/` directory contains legacy code migrating to `packages/squad-cli/` and `packages/squad-sdk/`. When moving code: + +1. Create the new file in the target package +2. Update imports in both locations +3. Ensure tests follow the file +4. Delete the old `src/` file once all references are updated +5. Document the migration in `.squad/agents/[name]/history.md` + +## Key Files + +- **src/index.ts** — CLI entry point and routing +- **src/resolution.ts** — Squad path resolution (repo vs. global) +- **.squad/decisions.md** — Team decisions and conventions +- **.squad/agents/[name]/charter.md** — Agent identity and expertise +- **package.json** — Workspace and script definitions + +## Questions? + +Open an issue or ask in `.squad/` discussion channels. The team is here to help. + +## License + +All contributions are MIT-licensed. By submitting a PR, you agree to this license. diff --git a/docs/src/content/docs/guide/contributors.md b/docs/src/content/docs/guide/contributors.md new file mode 100644 index 000000000..3781b4be6 --- /dev/null +++ b/docs/src/content/docs/guide/contributors.md @@ -0,0 +1,205 @@ +# Squad Contributors Guide + +Thank you to every contributor who has helped make Squad better. This page honors everyone who has submitted code, filed issues, started discussions, and shared ideas that have shaped this project. This page is updated with every release. + +## Code Contributors + +These community members submitted merged pull requests to Squad: + +### [@IEvangelist](https://github.com/IEvangelist) (David Pine) +Most recent: March 9, 2026 + +- [#298](https://github.com/bradygaster/squad/pull/298) — Active nav highlighting for Docs/Blog links, favicon fixes +- [#293](https://github.com/bradygaster/squad/pull/293) — Complete Astro docs site rebuild: Astro 5.7, Tailwind CSS, Pagefind search, responsive design, blog migration + +### [@diberry](https://github.com/diberry) (Dina Berry) +Most recent: March 9, 2026 + +- [#292](https://github.com/bradygaster/squad/pull/292) — Doc-impact review process for team workflows +- [#290](https://github.com/bradygaster/squad/pull/290) — .squad/ directory explainer for first-session guide +- [#288](https://github.com/bradygaster/squad/pull/288) — Installation method decision tree (CLI vs VS Code vs SDK) +- [#286](https://github.com/bradygaster/squad/pull/286) — Validation steps for Quick Start README + +### [@tamirdresher](https://github.com/tamirdresher) (Tamir Dresher) +Most recent: March 9, 2026 + +- [#283](https://github.com/bradygaster/squad/pull/283) — Dynamic blog discovery in docs-build test +- [#280](https://github.com/bradygaster/squad/pull/280) — Wire upstream and watch commands in CLI +- [#279](https://github.com/bradygaster/squad/pull/279) — Resolve pre-existing test failures +- [#278](https://github.com/bradygaster/squad/pull/278) — Release notes blog 026 + fix duplicate ADO blog +- [#272](https://github.com/bradygaster/squad/pull/272) — Renamed workstreams to SubSquads +- [#263](https://github.com/bradygaster/squad/pull/263) — Added CommunicationAdapter +- [#191](https://github.com/bradygaster/squad/pull/191) — Implemented Azure DevOps adapter +- [#225](https://github.com/bradygaster/squad/pull/225) — Wired upstream command + +### [@EmmittJ](https://github.com/EmmittJ) (Emmitt) +Most recent: March 7, 2026 + +- [#230](https://github.com/bradygaster/squad/pull/230) — Wired squad link + init --remote + +### [@williamhallatt](https://github.com/williamhallatt) (William Hallatt) +Most recent: March 7, 2026 + +- [#219](https://github.com/bradygaster/squad/pull/219) — Added fork contribution docs +- [#217](https://github.com/bradygaster/squad/pull/217) — Fixed init follow-up issue +- [#221](https://github.com/bradygaster/squad/pull/221) — Restored CI green status +- [#203](https://github.com/bradygaster/squad/pull/203) — Fixed init workflow +- [#185](https://github.com/bradygaster/squad/pull/185) — Fixed template path issue + +### [@jsturtevant](https://github.com/jsturtevant) (James Sturtevant) +Most recent: March 5, 2026 + +- [#198](https://github.com/bradygaster/squad/pull/198) — Added consult mode CLI + +### [@aadnesd](https://github.com/aadnesd) +Most recent: March 5, 2026 + +- [#204](https://github.com/bradygaster/squad/pull/204) — Fixed OpenTelemetry dependency issue + +### [@CarlosSardo](https://github.com/CarlosSardo) (Carlos Sardo) +Most recent: March 4, 2026 + +- [#178](https://github.com/bradygaster/squad/pull/178) — Added GitLab Issues walkthrough + +### [@codebytes](https://github.com/codebytes) (Chris Ayers) +Most recent: February 20, 2026 + +- [#97](https://github.com/bradygaster/squad/pull/97) — Created Star Trek casting universe + +### [@spboyer](https://github.com/spboyer) (Shayne Boyer) +Most recent: February 20, 2026 + +- [#57](https://github.com/bradygaster/squad/pull/57) — Implemented squad watch — Ralph watchdog + +### [@digitaldrummerj](https://github.com/digitaldrummerj) (Justin James) +Most recent: February 17, 2026 + +- [#89](https://github.com/bradygaster/squad/pull/89) — Added MCP Discord notifications + +### [@danielscholl](https://github.com/danielscholl) +Most recent: February 17, 2026 + +- [#80](https://github.com/bradygaster/squad/pull/80) — Implemented llms.txt docs build + +### [@csharpfritz](https://github.com/csharpfritz) (Jeffrey T. Fritz) +Most recent: February 13, 2026 + +- [#55](https://github.com/bradygaster/squad/pull/55) — Added logo for docs + +### [@dkirby-ms](https://github.com/dkirby-ms) (Dale Kirby) +Most recent: March 8, 2026 + +- [#243](https://github.com/bradygaster/squad/pull/243) — Fixed CLI blankspace issue + +## Community Contributors + +These community members filed issues and started discussions that drove improvements to Squad: + +### [@lbouriez](https://github.com/lbouriez) (Laurent) + +- [#267](https://github.com/bradygaster/squad/issues/267) — Reported credential leak (led to secret guardrails sprint) +- [#269](https://github.com/bradygaster/squad/issues/269) — Requested migration guide link + +### [@eric-vanartsdalen](https://github.com/eric-vanartsdalen) (Eric VanArtsdalen) + +- [#266](https://github.com/bradygaster/squad/issues/266) — Reported docs 403 error (led to docs build fix) + +### [@LasseAtSparkron](https://github.com/LasseAtSparkron) + +- [#265](https://github.com/bradygaster/squad/issues/265) — Reported ESM crash (led to Node 24 fix) + +### [@craigb](https://github.com/craigb) (Craig Boucher) + +- [#262](https://github.com/bradygaster/squad/issues/262) — Reported lint failure + +### [@marchermans](https://github.com/marchermans) (Marc Hermans) + +- [#247](https://github.com/bradygaster/squad/issues/247) — Reported installation failure + +### [@dfberry](https://github.com/dfberry) / [@diberry](https://github.com/diberry) (Dina Berry) + +- [#241](https://github.com/bradygaster/squad/issues/241) — Suggested docs member +- [#228](https://github.com/bradygaster/squad/issues/228) — Reported CI failure +- [#211](https://github.com/bradygaster/squad/issues/211) — Discussed management paradigms +- [#157](https://github.com/bradygaster/squad/issues/157) — Suggested CFO member + +### [@dkirby-ms](https://github.com/dkirby-ms) (Dale Kirby) + +- [#239](https://github.com/bradygaster/squad/issues/239) — Reported terminal flickering (led to TUI fix) + +### [@tomasherceg](https://github.com/tomasherceg) (Tomáš Herceg) + +- [#237](https://github.com/bradygaster/squad/issues/237) — Reported CLI wiring bug +- [#184](https://github.com/bradygaster/squad/issues/184) — Raised multi-PR commits issue + +### [@uvirk](https://github.com/uvirk) (Uday) + +- [#229](https://github.com/bradygaster/squad/issues/229) — Reported doctor command missing + +### [@EirikHaughom](https://github.com/EirikHaughom) (Eirik Haughom) + +- [#223](https://github.com/bradygaster/squad/issues/223) — Requested model configuration (led to per-model feature) + +### [@tihomir-kit](https://github.com/tihomir-kit) (Tihomir Kit) + +- [#214](https://github.com/bradygaster/squad/issues/214) — Reported node:sqlite error + +### [@fboucher](https://github.com/fboucher) (Frank Boucher) + +- [#207](https://github.com/bradygaster/squad/issues/207) — Reported non-root path resolution issue + +### [@Pruthviraj36](https://github.com/Pruthviraj36) + +- [#206](https://github.com/bradygaster/squad/issues/206) — Reported terminal blinking + +### [@cobey](https://github.com/cobey) (Cody Beyer) + +- [#196](https://github.com/bradygaster/squad/issues/196) — Requested global init mode + +### [@dnoriegagoodwin](https://github.com/dnoriegagoodwin) + +- [#195](https://github.com/bradygaster/squad/issues/195) — Reported upgrade version stamp bug + +### [@wbreza](https://github.com/wbreza) (Wallace Breza) + +- [#193](https://github.com/bradygaster/squad/issues/193) — Discussed ceremonies threshold + +### [@MdeBruin93](https://github.com/MdeBruin93) (MdeBruin) + +- [#192](https://github.com/bradygaster/squad/issues/192) — Reported npx stopped working + +### [@KevinUK](https://github.com/KevinUK) + +- [#188](https://github.com/bradygaster/squad/issues/188) — Reported upgrade doctor missing + +### [@jbruce716](https://github.com/jbruce716) + +- [#187](https://github.com/bradygaster/squad/issues/187) — Reported command not found + +### [@frankhaugen](https://github.com/frankhaugen) (Frank R. Haugen) + +- [#183](https://github.com/bradygaster/squad/issues/183) — Reported fetch failed error + +### [@chrislomonico](https://github.com/chrislomonico) + +- [#181](https://github.com/bradygaster/squad/issues/181) — Raised developer handover question + +### [@johnwc](https://github.com/johnwc) (John Carew) + +- [#176](https://github.com/bradygaster/squad/issues/176) — Requested multi-repo support + +### [@swnger](https://github.com/swnger) + +- [Discussion #169](https://github.com/bradygaster/squad/discussions/169) — Proposed skill-based orchestration (led to defineSkill()) + +### [@sturlath](https://github.com/sturlath) + +- [#156](https://github.com/bradygaster/squad/issues/156) — Discussed cross-agent learning + +### [@HemSoft](https://github.com/HemSoft) + +- [#148](https://github.com/bradygaster/squad/issues/148) — Proposed GitHub Agent Workflows concept + +--- + +**This page is updated with every release. No contribution goes unappreciated.** 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/src/content/docs/guide/shell.md b/docs/src/content/docs/guide/shell.md new file mode 100644 index 000000000..8ff557b7c --- /dev/null +++ b/docs/src/content/docs/guide/shell.md @@ -0,0 +1,343 @@ +# Interactive Shell Guide + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +> 💡 **Recommended: Use GitHub Copilot CLI** — The best way to interact with Squad today is through the [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli). Run `copilot --agent squad` to start a session with your team. The Copilot CLI provides the richest agent experience, including tool use, parallel execution, and full MCP integration. + +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 +``` + +### `/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) +``` + +Typical workflow — pick up where you left off: + +``` +squad > /sessions +squad > /resume a1b2 +squad > @Keaton, where were we on the auth work? +``` + +### `/clear` — Clear the screen + +Clears terminal output. + +### `/help` — Show all commands + +### `/quit` — Exit the shell + +Close the shell and return to your terminal. + +--- + +## Addressing Agents + +You can talk to specific agents by name: + +### Using `@AgentName` + +``` +squad > @Keaton, analyze the architecture of this project +``` + +### Using natural language + +``` +squad > Keaton, set up the database schema for user authentication +``` + +Or without naming an agent — the coordinator routes to whoever is best suited: + +``` +squad > Write a blog post about our new casting system +``` + +--- + +## Message Routing + +### How Messages Get to Agents + +1. **You type a message** → Shell receives it +2. **Coordinator 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 + +### 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, and any errors. + +### Resuming Work + +If an agent crashes or times out: + +``` +squad > @Keaton, check on Verbal and resume if needed +``` + +--- + +## Keyboard Shortcuts + +| Shortcut | Action | +|----------|--------| +| `↑` / `↓` | Scroll command history | +| `Ctrl+A` | Jump to start of line | +| `Ctrl+E` | Jump to end of line | +| `Ctrl+U` | Clear to start of line | +| `Ctrl+K` | Clear to end of line | +| `Ctrl+W` | Delete previous word | +| `Ctrl+C` | Exit shell | + +--- + +## Tips and Tricks + +### Check `/status` before big asks + +Before sending a complex task, check team status. If agents are already working, you might want to wait. + +### 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. + +### Batch work through the coordinator + +``` +squad > @Keaton, here's what needs doing: +1. Set up database schema +2. Build API endpoints +3. Write tests + +Prioritize and route, please. +``` + +The coordinator will decompose, prioritize, and launch agents efficiently. + +### Check `/history` after long waits + +If you step away, run `/history` to see what happened. Every decision is logged, every task is recorded. + +### Name agents explicitly for urgent work + +``` +squad > @Keaton, this is critical: we need the deployment script fixed +``` + +The explicit mention ensures the lead coordinator sees it first. + +--- + +## 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 +``` + +### Asking Agents About Their Work + +``` +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. + +### Custom Agent Chaining + +Instead of asking the coordinator to chain work, set up explicit hand-offs: + +``` +squad > @Keaton, when Verbal finishes the auth API, have him route testing to Fenster +``` + +--- + +## 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` + +--- + +## Troubleshooting + +### Shell Hangs or No Response + +The coordinator might be evaluating a complex task, or an agent might be streaming large output. Press `Ctrl+C` to interrupt, then check `/status`. + +### Agent Not Responding + +Check `/status` and `/history` for blockers. Then ask the coordinator to route explicitly: + +``` +squad > @Keaton, route this task to @Verbal and report any blocks +``` + +### Shell Quit Unexpectedly + +Run `squad` again to restart. Check `.squad/log/` for error context. + +--- + +## See Also + +- [CLI Reference](../reference/cli.md) — All CLI commands +- [VS Code](../features/vscode.md) — Squad in VS Code +- [Parallel Execution](../features/parallel-execution.md) — How agents fan out 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/src/content/docs/reference/api-reference.md b/docs/src/content/docs/reference/api-reference.md new file mode 100644 index 000000000..5815e8764 --- /dev/null +++ b/docs/src/content/docs/reference/api-reference.md @@ -0,0 +1,426 @@ +# 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 + +```typescript +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 + +Functions to locate Squad directories. + +### `resolveSquad(startPath?: string): string` + +Find `.squad/` directory starting from a path and walking up to the project root. Throws if not found. + +```typescript +const squadPath = resolveSquad(); +const squadPath = resolveSquad('/home/user/project/src'); +``` + +### `resolveGlobalSquadPath(): string` + +Get path to global personal squad (`~/.squad/` on Unix, `%USERPROFILE%\.squad\` on Windows). + +### `ensureSquadPath(startPath?: string): string` + +Like `resolveSquad()`, but creates the directory if it doesn't exist. + +--- + +## Runtime Constants + +### `MODELS: ModelCatalog` + +All supported models, organized by tier. + +```typescript +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', ...] +``` + +### `TIMEOUTS: TimeoutConfig` + +Standard timeout values for agent operations. + +```typescript +TIMEOUTS.agentInitMs; // 30000 (30s) +TIMEOUTS.agentExecuteMs; // 300000 (5 min) +TIMEOUTS.coordinatorRouteMs; // 5000 (5s) +``` + +### `AGENT_ROLES: Record` + +Standard agent roles and their default properties. + +--- + +## Configuration + +### `loadConfig(squadPath: string): Promise` + +Load configuration asynchronously. Reads `squad.config.ts` (if present), parses routing/model overrides, validates schemas. + +```typescript +const config = await loadConfig('./.squad'); +console.log(config.team.name); +console.log(Object.keys(config.agents)); +``` + +**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'; +} +``` + +### `loadConfigSync(squadPath: string): ConfigLoadResult` + +Synchronous version of `loadConfig()`. + +--- + +## Agents & Onboarding + +### `onboardAgent(options: OnboardOptions): Promise` + +Create a new agent directory, charter, and history file. + +```typescript +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', +}); +``` + +**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 + +### `CastingEngine` + +Generate agent personas from universe themes. + +```typescript +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' }, +]); +``` + +### `CastingHistory` + +Track all casting decisions over time. + +```typescript +const history = new CastingHistory('./.squad/casting'); +const records = history.getRecordsByAgent('lead'); +const previousCast = history.findByName('Stringer'); +``` + +**Types:** + +```typescript +interface CastMember { + name: string; + role: string; + universe: string; + displayName: string; +} +``` + +--- + +## Coordinator + +### `SquadCoordinator` + +Main class for routing work to agents. + +```typescript +const coordinator = new SquadCoordinator({ + teamRoot: './.squad', + enableParallel: true, +}); + +await coordinator.initialize(); + +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 + +await coordinator.execute(decision, 'refactor the API'); +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. + +### `getTier(name: TierName): TierDefinition` + +Get configuration for a specific tier (max agents, default model, available tools). + +--- + +## Tools + +### `defineTool(config: ToolConfig): SquadTool` + +Define a new tool with typed parameters. + +```typescript +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 }, + }; + }, +}); +``` + +### `ToolRegistry` + +Manage the built-in tool set. + +```typescript +const registry = new ToolRegistry('./.squad'); +const tools = registry.getTools(); +const agentTools = registry.getToolsForAgent(['squad_route', 'squad_decide']); +``` + +**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) + +Three-layer observability API for traces, metrics, and telemetry. + +### Layer 1: Low-Level Control + +```typescript +import { initializeOTel, shutdownOTel, getTracer, getMeter } from '@bradygaster/squad-sdk'; + +await initializeOTel({ + endpoint: 'http://localhost:4318', + serviceName: 'my-squad', +}); + +const tracer = getTracer('my-component'); +const meter = getMeter('my-component'); + +await shutdownOTel(); +``` + +### Layer 2: Mid-Level Bridge + +```typescript +import { bridgeEventBusToOTel, createOTelTransport } from '@bradygaster/squad-sdk'; + +const unsubscribe = bridgeEventBusToOTel(eventBus); +const transport = createOTelTransport(); +``` + +### Layer 3: High-Level Convenience + +```typescript +import { initSquadTelemetry } from '@bradygaster/squad-sdk'; + +const telemetry = await initSquadTelemetry({ + endpoint: 'http://localhost:4318', + serviceName: 'my-squad', + eventBus: myEventBus, +}); + +await telemetry.shutdown(); +``` + +--- + +## Streaming + +### `createReadableStream(response: unknown): ReadableStream` + +Convert an agent response to a readable stream. + +```typescript +const stream = createReadableStream(agentResponse); +const reader = stream.getReader(); +let result; + +while (!(result = await reader.read()).done) { + console.log(result.value); +} +``` + +--- + +## Upstream Inheritance + +### `readUpstreamConfig(squadPath: string): Promise` + +Load upstream sources from `.squad/upstream.json`. + +### `resolveUpstreams(config: UpstreamConfig, squadPath: string): Promise` + +Resolve all upstreams and return their inherited content. + +### `buildInheritedContextBlock(resolved: ResolvedUpstream[]): string` + +Build a markdown block of all inherited context (for agent charters). + +### `buildSessionDisplay(resolved: ResolvedUpstream[]): string` + +Build a human-readable display of upstream sources (for `squad status`). + +--- + +## 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 | + +--- + +## See Also + +- [SDK Reference](sdk.md) — Quick reference for common SDK usage +- [Integration Guide](integration.md) — Connecting to the Copilot SDK +- [Tools & Hooks](tools-and-hooks.md) — Custom tools and hook pipeline +- [Installation](../get-started/installation.md) — Getting started diff --git a/docs/reference/cli.md b/docs/src/content/docs/reference/cli.md similarity index 99% rename from docs/reference/cli.md rename to docs/src/content/docs/reference/cli.md index a91fbdbd0..c88d42f0e 100644 --- a/docs/reference/cli.md +++ b/docs/src/content/docs/reference/cli.md @@ -49,7 +49,7 @@ squad init | `squad aspire` | Launch Aspire dashboard for observability | No | | `squad aspire --docker` | Force Docker mode for Aspire | No | | `squad upstream add\|remove\|list\|sync` | Manage upstream Squad sources | Yes | -| `squad shell` | Launch interactive shell explicitly | No | +| `copilot --agent squad` | Launch interactive shell explicitly | No | | `squad nap` | Context hygiene (compress, prune, archive .squad/ state) | Yes | | `squad nap --deep` | Thorough cleanup with recursive descent | Yes | | `squad nap --dry-run` | Preview cleanup actions without changes | Yes | 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/src/content/docs/reference/glossary.md b/docs/src/content/docs/reference/glossary.md new file mode 100644 index 000000000..7a5ef32f9 --- /dev/null +++ b/docs/src/content/docs/reference/glossary.md @@ -0,0 +1,39 @@ +# Glossary + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +Key terms defined in one sentence each. Alphabetical order. + +--- + +**Agent** — A specialist AI team member with a role, charter, and persistent memory that handles specific types of work. + +**Casting** — The process of forming your team by proposing agents, confirming roles, and writing their charters to `.squad/`. + +**Ceremony** — A scheduled team event like retrospectives, reviews, or planning sessions defined in `.squad/ceremonies.md`. + +**Coordinator** — Squad's routing engine that reads your request, checks routing rules, and spawns the right agents. + +**Decisions** — Architectural choices, conventions, and directives captured in `.squad/decisions.md` that all agents read before working. + +**Directive** — A persistent rule or convention you give the team (like "Always use Zod for validation") that gets written to `decisions.md`. + +**History** — Each agent's memory of past work, stored in `.squad/agents/{name}/history.md` and read before every spawn. + +**Memory** — All persistent team state stored in the `.squad/` directory, including roster, routing rules, decisions, and agent histories. + +**Ralph** — The silent work monitor agent that watches your GitHub or GitLab issues and tracks work in progress. + +**Routing** — Rules in `.squad/routing.md` that define which agent handles which type of work, read by the coordinator before spawning. + +**Scribe** — The silent agent that tracks decisions and logs sessions, merging proposals from all agents into `.squad/decisions.md`. + +**Skill** — A reusable capability stored in `.squad/skills/` that agents can learn and execute. + +**Spawn** — The act of starting an agent as an independent subprocess with its own context window, tools, and memory. + +**Squad** — Your AI development team, coordinated through the Squad framework. + +**.squad/ directory** — The root directory containing all team state: roster, routing, decisions, agent charters and histories, and ceremony config. + +**Team** — The collection of agents working on your project, defined in `.squad/team.md`. diff --git a/docs/sdk/integration.md b/docs/src/content/docs/reference/integration.md similarity index 70% rename from docs/sdk/integration.md rename to docs/src/content/docs/reference/integration.md index dd28c9962..d50f823dc 100644 --- a/docs/sdk/integration.md +++ b/docs/src/content/docs/reference/integration.md @@ -2,21 +2,16 @@ > ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - -**Issue:** #34 (M0-10) +This guide covers connecting to the Copilot SDK via Squad's adapter layer, managing sessions, handling events, and recovering from errors. --- -## 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: +`SquadClient` wraps `@github/copilot-sdk` with lifecycle management and auto-reconnection: ```typescript -import { SquadClient } from '@squad/sdk'; +import { SquadClient } from '@bradygaster/squad-sdk'; const client = new SquadClient({ port: 3000, @@ -29,12 +24,14 @@ 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'; +import { SquadClientWithPool } from '@bradygaster/squad-sdk'; const squad = new SquadClientWithPool({ client: clientOptions, @@ -48,12 +45,14 @@ 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) => { +squad.events.on('session.created', (event) => { console.log(`Session ${event.sessionId} started`); }); @@ -66,6 +65,8 @@ squad.events.on('session.status_changed', (event) => { 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: @@ -82,8 +83,32 @@ try { } ``` -Error classes: `SDKConnectionError`, `SessionLifecycleError`, `ToolExecutionError`, `ModelAPIError`, `ConfigurationError`, `AuthenticationError`, `RateLimitError`, `RuntimeError`, `ValidationError`. Use `ErrorFactory` to wrap raw SDK errors with Squad context. +Error classes: + +| Class | Description | +|-------|-------------| +| `SDKConnectionError` | Connection failures (retryable) | +| `SessionLifecycleError` | Session create/destroy issues | +| `ToolExecutionError` | Tool handler failures | +| `ModelAPIError` | Model API call failures | +| `ConfigurationError` | Invalid configuration | +| `AuthenticationError` | Auth failures (fatal) | +| `RateLimitError` | Rate limit exceeded | +| `RuntimeError` | General runtime errors | +| `ValidationError` | Input validation failures | + +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. + +--- + +## See Also + +- [SDK API Reference](api-reference.md) — Full type and function reference +- [Tools & Hooks](tools-and-hooks.md) — Custom tools and hook pipeline +- [SDK Reference](sdk.md) — Quick reference 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/sdk/tools-and-hooks.md b/docs/src/content/docs/reference/tools-and-hooks.md similarity index 80% rename from docs/sdk/tools-and-hooks.md rename to docs/src/content/docs/reference/tools-and-hooks.md index 9d5d63a33..3de91366c 100644 --- a/docs/sdk/tools-and-hooks.md +++ b/docs/src/content/docs/reference/tools-and-hooks.md @@ -2,21 +2,16 @@ > ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - -**Issue:** #35 (M1-13) +Squad ships with 5 built-in tools and a hook pipeline for policy enforcement. This guide covers extending both. --- -## 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'; +import { ToolRegistry, defineTool } from '@bradygaster/squad-sdk'; const registry = new ToolRegistry(); @@ -39,14 +34,26 @@ const myTool = defineTool({ 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). +The handler returns a `ToolResult` with `success` flag and `data` payload. + +**Built-in tools:** + +| Tool | Purpose | +|------|---------| +| `route` | Dispatch to another agent | +| `decision` | Record a team decision | +| `memory` | Agent history | +| `status` | Session pool query | +| `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'; +import { HookPipeline, PreToolUseHook } from '@bradygaster/squad-sdk'; const auditHook: PreToolUseHook = async (toolName, params, context) => { console.log(`Agent ${context.agentId} calling ${toolName}`); @@ -57,6 +64,8 @@ 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: @@ -72,6 +81,8 @@ const sanitizeHook: PreToolUseHook = async (toolName, params, context) => { 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`: @@ -93,3 +104,11 @@ export default defineConfig({ }, }); ``` + +--- + +## See Also + +- [SDK API Reference](api-reference.md) — Full type and function reference +- [Integration Guide](integration.md) — Connecting to the Copilot SDK +- [Config Reference](config.md) — Configuration file options 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 92% rename from docs/scenarios/ci-cd-integration.md rename to docs/src/content/docs/scenarios/ci-cd-integration.md index e95df4341..3df64b85a 100644 --- a/docs/scenarios/ci-cd-integration.md +++ b/docs/src/content/docs/scenarios/ci-cd-integration.md @@ -28,8 +28,8 @@ The workflow is in `.github/workflows/squad-heartbeat.yml` and runs every 6 hour ```yaml name: Ralph Heartbeat on: - schedule: - - cron: '0 */6 * * *' # Every 6 hours + # schedule: + # - cron: '0 */6 * * *' # Every 6 hours workflow_dispatch: jobs: @@ -41,6 +41,8 @@ jobs: run: squad heartbeat ``` +> ⚡ **Cron is commented out by default.** The heartbeat schedule is disabled when Squad installs the workflow — it only runs via manual `workflow_dispatch` until you uncomment the `schedule` block. Be aware: enabling scheduled heartbeats will consume GitHub Actions minutes on every run. A 6-hour cron burns ~120 runs/month. Adjust the frequency to match your budget, or leave it manual and trigger heartbeats from the CLI with `squad heartbeat`. + Ralph reads `.squad/routing.md`, looks at open issues, and applies labels: ``` 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 67% rename from docs/scenarios/multi-codespace.md rename to docs/src/content/docs/scenarios/multi-codespace.md index 873e6390f..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 Workstreams - -> End-to-end walkthrough of running multiple Squad instances across Codespaces. - -## Background: The Tetris Experiment - -We validated Squad Workstreams by building a multiplayer Tetris game using 3 Codespaces, each running a separate workstream: - -| Codespace | Workstream | 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 workstream's label. - -## Setup Steps - -### 1. Create the workstreams config - -In your repository, create `.squad/workstreams.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 workstream 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 workstream 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 workstreams - -Use the CLI from any Codespace to see all workstreams: - -```bash -squad workstreams status -``` - - - - -## What Worked - -- **Clear separation**: Each workstream 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-workstream 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 workstreams (future work) - -## Lessons Learned - -1. **Keep workstreams independent** — design folder boundaries to minimize shared files -2. **Use branch-per-issue** — direct commits across workstreams cause merge hell -3. **Label everything** — unlabeled issues get lost between workstreams -4. **Start with 2 workstreams** — 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 95% rename from docs/scenarios/multiple-squads.md rename to docs/src/content/docs/scenarios/multiple-squads.md index c0ce28a8b..cd47e6c4d 100644 --- a/docs/scenarios/multiple-squads.md +++ b/docs/src/content/docs/scenarios/multiple-squads.md @@ -22,6 +22,8 @@ Squad's import system brings in a complete team — roster, charters, histories, **But** you can cherry-pick skills and knowledge manually. +> **Want continuous coordination instead?** If you need squads on different machines to see each other's live state (not just import once), see [Distributed Mesh](../features/distributed-mesh.md) — it syncs remote squad state via git and HTTP. + --- ## 2. Export from Each Repository 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/src/content/docs/scenarios/remote-qa.md b/docs/src/content/docs/scenarios/remote-qa.md new file mode 100644 index 000000000..944c31373 --- /dev/null +++ b/docs/src/content/docs/scenarios/remote-qa.md @@ -0,0 +1,85 @@ +# Remote Q&A with Squad + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + + +**Try this:** +``` +@copilot How does authentication work in this project? +``` + +You don't always have the repo cloned locally. Sometimes you want to ask your Squad a question from the browser, the GitHub CLI, or a mobile device — without pulling code. + +--- + +## Current options + +Squad already supports several remote interaction paths. Each trades off convenience, depth, and setup effort. + +### 1. Copilot Chat with squad.agent.md + +If the repo has `.github/agents/squad.agent.md`, GitHub Copilot Chat reads it automatically when you ask questions about the repo. + +**How it works:** +- Open the repo in GitHub.com +- Use Copilot Chat in the browser +- Copilot reads the agent file and answers using your team's context + +**Good for:** Quick questions about architecture, team structure, and project conventions. + +**Limitation:** Copilot reads the default branch only. You can't point it at a feature branch. + +### 2. Assign an issue to @copilot + +Create a GitHub issue and assign it to `@copilot`. If the repo has Squad's issue-assign workflow (`.github/workflows/squad-issue-assign.yml`), the coding agent picks up the issue and works it using your Squad configuration. + +**How it works:** +1. Create an issue describing the question or task +2. Assign it to `@copilot` +3. The workflow triggers and Squad processes it + +**Good for:** Tasks that need code changes, research across files, or multi-step investigation. + +**Limitation:** Designed for work items, not conversational Q&A. The workflow runs against the default branch. + +### 3. Use `squad:` labels on issues + +Add a `squad:{member}` label to any issue, and Squad routes it to the right team member. + +**How it works:** +1. Create or label an issue with `squad:fenster` (or any member name) +2. The triage workflow assigns it to the appropriate agent +3. Work proceeds through the normal Squad flow + +**Good for:** Routing specific work to specific team members without cloning. + +**Limitation:** Requires label setup on the repo. Routes work, not questions. + +--- + +## What's not supported yet + +These features don't exist today but would make remote Q&A more powerful: + +### Branch-aware queries + +All current remote paths read the default branch. You can't ask "How does auth work on the `feature/oauth` branch?" and get branch-specific answers. + +**Workaround:** Mention the branch in your question and ask the agent to check out that branch during investigation. + +### GitHub Discussions integration + +A Discussions-based Q&A channel where Squad monitors and answers questions would make remote interaction feel conversational. This would need a new workflow trigger on `discussion` events. + +### Issue comment commands + +A `/squad ask "question"` command in issue comments that triggers Squad to respond inline would enable threaded Q&A without creating new issues. + +--- + +## Tips + +- **Start with Copilot Chat.** It's the lowest-effort path and works today for repos with `squad.agent.md`. +- **Use issues for anything that needs code.** Copilot Chat answers questions; issues drive work. +- **Include context in your question.** Remote paths don't have your local state. Be specific about which files, features, or branches you mean. +- **Check the default branch.** All remote paths currently read `main` (or whatever the repo's default branch is). If you're asking about unreleased work, mention the branch explicitly. diff --git a/docs/scenarios/scaling-workstreams.md b/docs/src/content/docs/scenarios/scaling-workstreams.md similarity index 67% rename from docs/scenarios/scaling-workstreams.md rename to docs/src/content/docs/scenarios/scaling-workstreams.md index 79ab13270..3730533a7 100644 --- a/docs/scenarios/scaling-workstreams.md +++ b/docs/src/content/docs/scenarios/scaling-workstreams.md @@ -1,165 +1,168 @@ -# Scaling with Workstreams - -> 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: Workstreams - -Workstreams partition a repo's issues into labeled subsets. Each Codespace (or machine) runs one workstream, 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 workstream label. │ -└─────────────────────────────────────────────────┘ -``` - -## Quick Start - -### 1. Define workstreams - -Create `.squad/workstreams.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 workstream. Ralph will only pick up issues matching the active workstream's label. - -### 3. Activate a workstream - -**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 workstreams activate bridge -``` -This writes a `.squad-workstream` file (gitignored — local to your machine). - -**Option C — Single workstream auto-select:** -If `workstreams.json` defines only one workstream, 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 workstreams -squad workstreams list - -# Show activity per workstream (branches, PRs) -squad workstreams status - -# Activate a workstream for this machine -squad workstreams activate engine - -# Backward compat alias -squad streams list -``` - -## 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 workstream 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-Workstream - -You don't need multiple Codespaces to test. Use `squad workstreams activate` to switch between workstreams sequentially on a single machine. - -## Resolution Chain - -Squad resolves the active workstream in this order: - -1. `SQUAD_TEAM` environment variable -2. `.squad-workstream` file (written by `squad workstreams activate`) -3. Auto-select if exactly one workstream is defined -4. No workstream → single-squad mode (backward compatible) - -## Monitoring - -Use `squad workstreams status` to see all workstreams' activity: - -``` -Configured Workstreams - - 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 workstream resolved via: env -``` - -## See Also - -- [Multi-Codespace Setup](multi-codespace.md) — Walkthrough of the Tetris experiment -- [Workstreams PRD](../specs/streams-prd.md) — Full specification -- [Workstreams 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](https://github.com/bradygaster/squad/blob/main/docs/_internal/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 76% rename from docs/scenarios/troubleshooting.md rename to docs/src/content/docs/scenarios/troubleshooting.md index 89763683f..913e4c3c2 100644 --- a/docs/scenarios/troubleshooting.md +++ b/docs/src/content/docs/scenarios/troubleshooting.md @@ -4,6 +4,18 @@ Common issues and fixes for Squad installation and usage. --- +## Quick fixes + +| Error | Cause | Fix | +|-------|-------|-----| +| `squad: command not found` | Squad CLI not installed or not in PATH | Run `npm install -g @bradygaster/squad-cli` or use `npx @bradygaster/squad-cli` | +| `No .squad/ directory found` | Not in a git repo or Squad not initialized | Run `git init` then `npx squad init` | +| `Cannot find agent "{name}"` | Agent doesn't exist in `.squad/agents/` | Check `.squad/team.md` for roster, or re-run casting | +| `gh: command not found` | GitHub CLI not installed | Install from [cli.github.com](https://cli.github.com/) then `gh auth login` | +| `Node.js version error` | Node.js version below v20 | Upgrade Node.js to v20+ (see below) | + +--- + ## `npx github:bradygaster/squad` appears to hang **Problem:** Running the install command shows a frozen npm spinner. Nothing happens. @@ -62,7 +74,7 @@ Common issues and fixes for Squad installation and usage. **Problem:** `npx github:bradygaster/squad` fails with an engine compatibility error, or Squad behaves unexpectedly. -**Cause:** Squad requires Node.js 22.0.0 or later (enforced via `engines` in `package.json`). +**Cause:** Squad requires Node.js 20.0.0 or later (LTS), enforced via `engines` in `package.json`. **Fix:** @@ -70,9 +82,9 @@ Common issues and fixes for Squad installation and usage. node --version ``` -If below v22, upgrade Node.js: -- **nvm (macOS/Linux):** `nvm install 22 && nvm use 22` -- **nvm-windows:** `nvm install 22 && nvm use 22` +If below v20, upgrade to the latest LTS: +- **nvm (macOS/Linux):** `nvm install --lts && nvm use --lts` +- **nvm-windows:** `nvm install lts && nvm use lts` - **Direct download:** [nodejs.org](https://nodejs.org/) --- diff --git a/docs/scenarios/upgrading.md b/docs/src/content/docs/scenarios/upgrading.md similarity index 98% rename from docs/scenarios/upgrading.md rename to docs/src/content/docs/scenarios/upgrading.md index 75b93a91a..7c98d7da5 100644 --- a/docs/scenarios/upgrading.md +++ b/docs/src/content/docs/scenarios/upgrading.md @@ -83,7 +83,7 @@ git commit -m "chore: migrate .ai-team/ → .squad/" **Timeline:** `.ai-team/` support continues through v0.6.0. Migration becomes required in v1.0.0. -**Full details:** See the [Migration Guide](../migration/v0.5.0-squad-rename.md). +**Full details:** See the [Migration Guide](../get-started/migration.md). --- diff --git a/docs/sdk-first-mode.md b/docs/src/content/docs/sdk-first-mode.md similarity index 99% rename from docs/sdk-first-mode.md rename to docs/src/content/docs/sdk-first-mode.md index 040e53a42..eaad7131e 100644 --- a/docs/sdk-first-mode.md +++ b/docs/src/content/docs/sdk-first-mode.md @@ -832,5 +832,5 @@ export default defineSquad({ ## See Also - [SDK Reference](./reference/sdk.md) — all SDK exports -- [Routing Guide](./concepts/routing.md) — deep dive on routing tiers -- [Governance & Hooks](./sdk/tools-and-hooks.md) — hook pipeline and governance +- [Routing Guide](./features/routing.md) — deep dive on routing tiers +- [Governance & Hooks](./reference/sdk.md) — hook pipeline and governance 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..fe6b5a4b4 --- /dev/null +++ b/docs/src/layouts/BaseLayout.astro @@ -0,0 +1,49 @@ +--- +interface Props { + title: string; + description?: string; +} + +import squadLogo from '../assets/images/squad-logo.png'; +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 fullTitle = `${title} — Squad Docs`; +const canonicalUrl = Astro.site ? new URL(Astro.url.pathname, Astro.site).href : undefined; +const ogImage = Astro.site ? new URL(squadLogo.src, Astro.site).href : squadLogo.src; +--- + + + + + + + + + + {fullTitle} + + + + + + + {canonicalUrl && } + + + + + + + + + + + + + diff --git a/docs/src/layouts/DocsLayout.astro b/docs/src/layouts/DocsLayout.astro new file mode 100644 index 000000000..63cf0d150 --- /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..94e425161 --- /dev/null +++ b/docs/src/navigation.ts @@ -0,0 +1,144 @@ +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: 'Quick start', slug: 'get-started/five-minute-start' }, + { title: 'Installation', slug: 'get-started/installation' }, + { title: 'Choose your path', slug: 'get-started/choosing-your-path' }, + { 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: 'Interactive Shell', slug: 'guide/shell' }, + { 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: 'Distributed Mesh', slug: 'features/distributed-mesh' }, + ], + }, + { + title: 'Reference', + dir: 'reference', + items: [ + { title: 'CLI', slug: 'reference/cli' }, + { title: 'SDK', slug: 'reference/sdk' }, + { title: 'SDK API Reference', slug: 'reference/api-reference' }, + { title: 'SDK Integration', slug: 'reference/integration' }, + { title: 'Tools & Hooks', slug: 'reference/tools-and-hooks' }, + { title: 'Config', slug: 'reference/config' }, + { title: 'Glossary', slug: 'reference/glossary' }, + ], + }, + { + 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: 'Remote Q&A', slug: 'scenarios/remote-qa' }, + { 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: 'Architecture', slug: 'concepts/architecture' }, + { 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.

+ +
+