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..cdc2b79dd --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,22 @@ +import { defineConfig } from 'astro/config'; +import tailwindcss from '@tailwindcss/vite'; +import { remarkRewriteLinks } from './src/plugins/remark-rewrite-links.mjs'; +import { rehypePagefindAttrs } from './src/plugins/rehype-pagefind-attrs.mjs'; + +export default defineConfig({ + site: 'https://bradygaster.github.io', + base: '/squad/', + vite: { + plugins: [tailwindcss()], + }, + markdown: { + remarkPlugins: [remarkRewriteLinks], + rehypePlugins: [rehypePagefindAttrs], + shikiConfig: { + themes: { + light: 'github-light', + dark: 'github-dark', + }, + }, + }, +}); diff --git a/docs/blog/2026-03-17-ado-configurable-work-items.md b/docs/blog/2026-03-17-ado-configurable-work-items.md new file mode 100644 index 000000000..afd5a9616 --- /dev/null +++ b/docs/blog/2026-03-17-ado-configurable-work-items.md @@ -0,0 +1,277 @@ +--- +title: "ADO Configurable Work Items: Match Your Process" +date: 2026-03-17 +author: "Squad (Copilot)" +wave: null +tags: [squad, azure-devops, ado, work-items, configuration] +status: published +hero: "Squad now adapts to your Azure DevOps process template. Automatically detect available work item types, area paths, and iterations. No more hardcoded defaults." +--- + +# ADO Configurable Work Items: Match Your Process + +> _Use any Azure DevOps process template. Squad introspects your project, learns your structure, and creates work items the way your team works._ + +## The Problem + +Squad originally hardcoded work item creation: always User Stories, always in the default area, no iterations. This worked for simple projects but broke with reality: + +- Scrum teams use different types than Agile teams +- Some teams organize by component, others by team +- Custom process templates add specialized types +- Iterations/sprints matter for sprint planning + +As a result: +- Squad created work items in the wrong area +- Wrong work item types appearing in backlog +- Ralph (work monitor) created clutter, not structure + +Organizations had to work around Squad instead of Squad adapting to their workflow. + +## How It Works + +### Auto-Discovery + +During squad initialization: + +```bash +squad init --org contoso --project "My Project" --introspect +``` + +Squad connects to your ADO project and discovers: + +✓ Available work item types (Bug, Task, User Story, Feature, Scenario, etc.) +✓ Area paths (team/component organization) +✓ Iterations and sprints +✓ Custom fields + +Suggests a config based on what exists. + +### Configuration + +Store your preferences in `.squad/config.json`: + +```json +{ + "ado": { + "org": "contoso", + "project": "Platform", + "defaultWorkItemType": "User Story", + "areaPath": "Platform\Backend Services", + "iterationPath": "Platform\Sprint 5" + } +} +``` + +### Validation + +Before creating work items, validate: + +```bash +squad config validate +``` + +Returns: +``` +✓ Organization: contoso +✓ Project: Platform +✓ Work Item Type: User Story (exists) +✓ Area Path: Platform\Backend Services (exists) +✓ Iteration: Platform\Sprint 5 (exists) +``` + +### Creation + +When Ralph monitors work: + +```bash +squad ralph scan +``` + +Creates issues as: +- **Type**: Your configured `defaultWorkItemType` +- **Area**: Your configured `areaPath` +- **Iteration**: Your configured `iterationPath` (if set) + +Issues appear in the right backlog, organized correctly. + +## Real-World Scenario + +### Before: Hardcoded Approach + +Squad creates all issues as "User Story" in default area → Scrum backlog is polluted with non-stories, area organization is ignored. + +### After: Configurable Approach + +**Backend Team** runs their squad with: +```json +{ + "defaultWorkItemType": "User Story", + "areaPath": "Platform\Backend" +} +``` + +**QA Team** runs their squad with: +```json +{ + "defaultWorkItemType": "Bug", + "areaPath": "Platform\QA" +} +``` + +**DevOps Team** runs their squad with: +```json +{ + "defaultWorkItemType": "Task", + "areaPath": "Platform\Infrastructure" +} +``` + +Now: +- Backend issues show as User Stories in the Backend area ✓ +- QA issues show as Bugs in the QA area ✓ +- DevOps issues show as Tasks in the Infrastructure area ✓ +- Each team's backlog stays organized ✓ +- Ralph creates work that makes sense for each team ✓ + +## Process Template Support + +Works with all Azure DevOps templates: + +### Scrum +- Types: Epic, Feature, User Story, Task, Bug, Impediment +- Areas: Team structure (Team 1, Team 2) +- Iterations: Sprint cycles (Sprint 1, Sprint 2, etc.) + +### Agile +- Types: Epic, Feature, User Story, Task, Bug, Issue +- Areas: Component-based (Web, API, Database) +- Iterations: Release cycles (Release 1, Release 2) + +### CMMI +- Types: Epic, Feature, Requirement, Task, Bug, Review, Issue +- Areas: Department structure +- Iterations: Phase-based (Planning, Dev, Test, Deploy) + +### Custom Templates +Any custom template is supported. Introspect to see what's available. + +## Configuration Reference + +In `.squad/config.json`, add an `ado` section: + +```json +{ + "ado": { + "org": "your-org-name", + "project": "Your Project", + "defaultWorkItemType": "User Story", + "areaPath": "Your Project\Team Name", + "iterationPath": "Your Project\Sprint 1" + } +} +``` + +All fields optional. Defaults: +- **defaultWorkItemType**: `"User Story"` +- **areaPath**: Project root +- **iterationPath**: None (not assigned to sprint) + +## Introspection Workflow + +### Step 1: Connect + +```bash +squad init --org contoso --project "Platform" --introspect +``` + +### Step 2: Review Suggestions + +Squad prints discovered options: +``` +Available Work Item Types: + - User Story + - Task + - Bug + - Epic + - Feature + +Available Areas: + - Platform + - Platform\Backend + - Platform\Frontend + - Platform\QA + +Available Iterations: + - Platform\Sprint 1 + - Platform\Sprint 2 + - Platform\Sprint 3 +``` + +### Step 3: Configure + +Update `.squad/config.json` with your choices. + +### Step 4: Validate + +```bash +squad config validate +``` + +### Step 5: Use + +Ralph now creates work items correctly. + +## Overrides + +Override defaults for specific work items: + +```bash +squad create issue "Critical bug" --type Bug --areaPath "Platform\QA" +``` + +Or in code: +```typescript +squad.createWorkItem({ + title: "Setup logging", + type: "Task", + areaPath: "Platform\Infrastructure", + iterationPath: "Platform\Sprint 5" +}); +``` + +## Multi-Team Setup + +Each team/squad has their own config: + +**squad-backend/.squad/config.json**: +```json +{ "ado": { "defaultWorkItemType": "User Story", "areaPath": "Platform\Backend" } } +``` + +**squad-frontend/.squad/config.json**: +```json +{ "ado": { "defaultWorkItemType": "User Story", "areaPath": "Platform\Frontend" } } +``` + +**squad-qa/.squad/config.json**: +```json +{ "ado": { "defaultWorkItemType": "Bug", "areaPath": "Platform\QA" } } +``` + +## Fallback Behavior + +If config is missing or invalid: + +1. Attempts to use configured values +2. Falls back to defaults if not found: + - Work item type → "User Story" + - Area → Project root + - Iteration → None +3. Logs warnings when fallback occurs + +## See Also + +- [Persistent Ralph](/features/persistent-ralph) — Ralph creates work with your config +- [Cross-Squad Orchestration](/features/cross-squad-orchestration) — Delegate work with correct types +- [Generic Scheduler](/features/generic-scheduler) — Run ADO operations on schedule diff --git a/docs/blog/2026-03-17-cross-squad-orchestration.md b/docs/blog/2026-03-17-cross-squad-orchestration.md new file mode 100644 index 000000000..ea25d2165 --- /dev/null +++ b/docs/blog/2026-03-17-cross-squad-orchestration.md @@ -0,0 +1,266 @@ +--- +title: "Cross-Squad Orchestration: Work as a Network" +date: 2026-03-17 +author: "Squad (Copilot)" +wave: null +tags: [squad, orchestration, discovery, delegation, mesh] +status: published +hero: "Squads discover each other's capabilities and delegate work directly. No email chains, no context-switching—just structured, traceable collaboration." +--- + +# Cross-Squad Orchestration: Work as a Network + +> _Discover what other squads can do, delegate work to the right team, and build a connected mesh of specialized squads._ + +## The Problem + +In large organizations, work routing is chaotic: + +- A feature squad has a deployment problem → email to the infra squad +- Infra squad is overloaded → 3-day turnaround +- QA squad has capacity but nobody knows → work stalls + +Alternatively, squads work in isolation: + +- Each team maintains their own skills and patterns +- No visibility into what other squads know +- Repeated effort across teams + +Existing solutions (Jira hierarchies, manual registries, email lists) don't scale and create friction. + +Cross-squad orchestration solves this by making squads **discoverable and delegatable**. + +## How It Works + +### Publish Capabilities + +Each squad publishes `.squad/manifest.json`: + +```json +{ + "name": "infra-squad", + "capabilities": ["kubernetes", "terraform", "ci-cd"], + "accepts": ["issues"], + "contact": { + "labels": ["squad:infra", "priority:system"] + } +} +``` + +### Discover Squads + +```bash +squad discover +``` + +Your squad reads upstream manifests and builds a local index of known squads. + +### Delegate Work + +```bash +squad delegate infra-squad "Set up autoscaling for staging cluster" +``` + +An issue is created in infra-squad's repo with: +- Your squad context +- Proper labels for routing +- Link back to original request + +## Real-World Example + +### A Day in the Network + +**Morning**: Frontend squad needs a new API endpoint +```bash +squad delegate backend-squad "Create /api/v2/user-preferences endpoint" +``` +- Issue appears in backend-squad's backlog labeled `squad:frontend` + `api:user-preferences` +- Backend squad sees the full request and can estimate + +**Mid-morning**: Frontend squad discovers performance issues +```bash +squad delegate devops-squad "Profile and optimize React bundle size" +``` +- DevOps squad uses their profiling tools +- Returns findings back via PR comment + +**Afternoon**: Platform squad needs database migration +```bash +squad delegate dba-squad --file migration-plan.md +``` +- Plan is reviewed and approved +- DBA squad runs it during maintenance window + +**Next day**: DevOps squad learns an optimization technique +```bash +squad upstream propose platform-squad --skills +``` +- Shares the learning back upstream +- Frontend squad auto-syncs the skill + +## Configuration + +### Squad Manifest + +Place at `.squad/manifest.json`: + +```json +{ + "name": "my-squad", + "repo": "github.com/org/my-squad", + "description": "Handles user-facing API and client SDKs", + "capabilities": [ + "rest-api", + "graphql", + "sdk-generation", + "authentication" + ], + "accepts": [ + "issues", + "pull-requests" + ], + "contact": { + "team": "Backend Platform", + "labels": [ + "squad:backend", + "epic:api", + "priority:high" + ] + } +} +``` + +### Register Upstreams + +Squad discovery reads `.squad/upstream.json`: + +```json +{ + "upstreams": [ + { + "name": "platform-squad", + "source": "https://github.com/org/platform-squad", + "ref": "main" + } + ] +} +``` + +## Delegation Process + +When you delegate: + +1. Squad resolves the target squad name from discovery index +2. Creates a GitHub issue in the target repo +3. Applies labels from target's manifest +4. Includes cross-squad metadata (source, context) +5. Posts a comment in your squad linking to the created issue + +Example issue created in infra-squad: + +``` +Title: [DELEGATED] Create staging autoscaling policy + +From: feature-squad (#42 in original repo) +--- + +Please help us set up autoscaling for our staging cluster. +We're hitting ~80% CPU during peak load and need to scale to handle 2x traffic. + +Acceptance Criteria: +- Autoscaling configured for staging-app deployment +- Min replicas: 2, max: 10 +- Target: 70% CPU, 80% memory +- Verify with load test + +Labels: squad:feature, epic:performance, priority:high +``` + +## Use Cases + +### Matrix Organization + +``` +Platform Squad +├── Backend Squad (delegates infra work) +├── Frontend Squad (delegates performance work) +└── QA Squad (delegates automation work) +``` + +Each squad specializes. Work flows naturally to the right team. + +### Multi-Org Networks + +``` +Org A (Product) +├── Feature Squad A +└── Feature Squad B + +Org B (Platform) +├── Infra Squad +└── Data Squad +``` + +Cross-org squads delegate via upstreams. Org B squads handle infrastructure for Org A. + +### Shared Services + +``` +Platform/ +├── Auth Squad (auth policies, tokens, SSO) +├── Database Squad (migrations, optimization, backups) +└── Observability Squad (logging, metrics, tracing) +``` + +Any squad discovering Platform can delegate auth, database, or observability work. + +## Best Practices + +### Capability Naming + +Use specific, searchable terms: + +```json +{ + "capabilities": [ + "kubernetes-eks", + "terraform-aws", + "helm-charts", + "ci-github-actions" + ] +} +``` + +Not: `["devops"]` + +### Contact Labels + +Make it easy for squads to find your backlog: + +```json +{ + "contact": { + "labels": [ + "squad:platform", + "area:infrastructure", + "severity:normal" + ] + } +} +``` + +### Documentation + +Link to squad docs in the description: + +```json +{ + "description": "Kubernetes clusters, Terraform infra, CI/CD. See https://wiki.org/platform-squad for runbooks and policies." +} +``` + +## See Also + +- [Upstream Auto-Sync](/features/upstream-sync) — Keep squad manifests in sync +- [Persistent Ralph](/features/persistent-ralph) — Monitor delegation status +- [Generic Scheduler](/features/generic-scheduler) — Schedule recurring delegations diff --git a/docs/blog/2026-03-17-generic-scheduler.md b/docs/blog/2026-03-17-generic-scheduler.md new file mode 100644 index 000000000..696bf3ae6 --- /dev/null +++ b/docs/blog/2026-03-17-generic-scheduler.md @@ -0,0 +1,306 @@ +--- +title: "Generic Scheduler: Unified Task Orchestration" +date: 2026-03-17 +author: "Squad (Copilot)" +wave: null +tags: [squad, scheduler, automation, cron, tasks] +status: published +hero: "Stop scattering cron jobs, polling scripts, and manual triggers. Define all recurring squad tasks in one place and let Squad run them locally or on GitHub Actions." +--- + +# Generic Scheduler: Unified Task Orchestration + +> _One config file. Local polling or GitHub Actions. Cron, interval, event-driven, or startup triggers. Squad runs your tasks reliably._ + +## The Problem + +Squads need to run recurring tasks: +- Ralph monitors work every 5 minutes +- Upstream sync runs every 6 hours +- Daily reports generate at 9am +- Deployment notifications trigger on push + +Today, these are scattered across different systems: +- Some use `cron` on a local machine (breaks if machine stops) +- Some use GitHub Actions (hard to run locally, different syntax) +- Some use custom polling scripts (duplicated logic everywhere) +- Some are manual (easy to forget) + +No unified way to orchestrate, monitor, or test. + +## How It Works + +### One Config, Two Runtimes + +Define your schedule once in `.squad/schedule.json`: + +```json +{ + "schedules": [ + { + "id": "ralph-heartbeat", + "trigger": { "type": "interval", "intervalSeconds": 300 }, + "task": { "type": "script", "command": "squad ralph watch --duration 25s" }, + "providers": ["local-polling", "github-actions"] + } + ] +} +``` + +Run it **locally**: +```bash +squad schedule watch +``` + +Or **in GitHub Actions** (auto-generated): +```bash +squad schedule init-ci +``` + +Same config, both runtimes work. + +## Real-World Example + +### A Squad's Daily Routine + +**Morning**: Deploy latest code +```json +{ + "id": "deploy-staging", + "trigger": { "type": "cron", "expression": "0 8 * * MON-FRI" }, + "task": { "type": "workflow", "ref": ".github/workflows/deploy-staging.yml" }, + "providers": ["github-actions"] +} +``` + +**Every hour**: Check upstream for updates +```json +{ + "id": "sync-upstream", + "trigger": { "type": "cron", "expression": "0 * * * *" }, + "task": { "type": "script", "command": "squad upstream sync" }, + "providers": ["github-actions"] +} +``` + +**Every 5 minutes**: Monitor work queue (local only) +```json +{ + "id": "ralph-heartbeat", + "trigger": { "type": "interval", "intervalSeconds": 300 }, + "task": { "type": "script", "command": "squad ralph watch --duration 25s" }, + "providers": ["local-polling"] +} +``` + +**At startup**: Initialize metrics +```json +{ + "id": "init-metrics", + "trigger": { "type": "startup" }, + "task": { "type": "script", "command": "mkdir -p .squad/metrics" }, + "providers": ["local-polling"] +} +``` + +### Workflow + +**Morning at 8am**: +- GitHub Actions triggers `deploy-staging` +- Deployment completes, logs available in GitHub UI + +**Throughout the day**: +- Every hour, `sync-upstream` runs to check for parent changes +- Every 5 minutes (if you're running `squad schedule watch`), Ralph checks work + +**Failure scenario**: +- A sync attempt fails (network issue) +- Scheduler waits 30 seconds (backoff) +- Retries automatically +- Logs to `.squad/.schedule-state.json` + +## Trigger Types + +### Interval +Run every N seconds: +```json +{ "type": "interval", "intervalSeconds": 300 } // Every 5 minutes +``` + +### Cron +Standard cron syntax: +```json +{ "type": "cron", "expression": "0 8 * * MON-FRI" } // 8am Mon-Fri +``` + +Common patterns: +- `"0 * * * *"` — Every hour +- `"0 0 * * *"` — Daily at midnight +- `"0 */6 * * *"` — Every 6 hours +- `"*/5 * * * *"` — Every 5 minutes (GitHub Actions only) + +### Event +Run when something happens: +```json +{ "type": "event", "eventName": "session:complete" } +``` + +Built-in events: +- `session:start` — Squad initializes +- `session:complete` — Squad finishes +- `agent:milestone` — Agent reaches checkpoint +- `error:uncaught` — Error occurs + +### Startup +Run once when squad initializes: +```json +{ "type": "startup" } +``` + +## Task Types + +### Script +Run a shell command: +```json +{ "type": "script", "command": "squad upstream sync --auto-pr" } +``` + +### Workflow +Trigger a GitHub Actions workflow: +```json +{ "type": "workflow", "ref": ".github/workflows/daily-report.yml", "inputs": { "format": "markdown" } } +``` + +### Copilot +Run a Copilot agent task: +```json +{ "type": "copilot", "agent": "ralph", "prompt": "summarize work status" } +``` + +### Webhook +POST to a URL: +```json +{ "type": "webhook", "url": "https://api.example.com/hooks/squad-task", "method": "POST" } +``` + +## Providers + +### Local Polling +Run in-process when you run `squad schedule watch`: +```json +{ "providers": ["local-polling"] } +``` + +Best for development and testing. Runs until you stop it. + +### GitHub Actions +Automatically generate GitHub Actions workflows: +```json +{ "providers": ["github-actions"] } +``` + +Best for production. Runs 24/7 on GitHub's infrastructure. Squad generates `.github/workflows/schedule-{id}.yml` files. + +## Configuration Reference + +```json +{ + "schedules": [ + { + "id": "unique-identifier", + "name": "Human-readable name", + "description": "What this task does", + "enabled": true, + "trigger": { + "type": "interval|cron|event|startup", + ... + }, + "task": { + "type": "script|workflow|copilot|webhook", + ... + }, + "providers": ["local-polling", "github-actions"], + "retry": { + "maxRetries": 2, + "backoffSeconds": 5 + }, + "tags": ["monitoring", "core"], + "timeout": 300 + } + ] +} +``` + +## Monitoring + +Check schedule status anytime: +```bash +squad schedule status +``` + +Output shows: +- Last run time and result +- Next scheduled run time +- Total runs and failure count +- Current status (running, waiting, error) + +View detailed logs: +```bash +squad schedule logs ralph-heartbeat +``` + +## Error Handling + +Schedules include configurable retry: + +```json +{ + "retry": { + "maxRetries": 2, + "backoffSeconds": 5 + } +} +``` + +On failure: +1. Wait 5 seconds (backoff) +2. Retry attempt 1 +3. Wait 10 seconds (exponential backoff) +4. Retry attempt 2 +5. If still failing, log error and continue + +## Use Cases + +### Monitoring +```bash +squad schedule init ralph-monitor --trigger interval:300 +``` + +Ralph checks work every 5 minutes. + +### CI/CD Integration +```bash +squad schedule init deploy --trigger "cron:0 8 * * *" --task workflow:.github/workflows/deploy.yml +``` + +Deploy every morning at 8am. + +### Syncing +```bash +squad schedule init sync-upstream --trigger "cron:0 * * * *" --providers github-actions +``` + +Sync from parent every hour (GitHub Actions only). + +### Notifications +```bash +squad schedule init slack-report --trigger "cron:0 9 * * MON-FRI" --task webhook:https://hooks.slack.com/... +``` + +Send daily standup to Slack on weekday mornings. + +## See Also + +- [Persistent Ralph](/features/persistent-ralph) — Monitor agent activity +- [Upstream Auto-Sync](/features/upstream-sync) — Sync squads on schedule +- [Cross-Squad Orchestration](/features/cross-squad-orchestration) — Delegate recurring work diff --git a/docs/blog/2026-03-17-persistent-ralph.md b/docs/blog/2026-03-17-persistent-ralph.md new file mode 100644 index 000000000..acede992f --- /dev/null +++ b/docs/blog/2026-03-17-persistent-ralph.md @@ -0,0 +1,348 @@ +--- +title: "Persistent Ralph: Monitor Squad Health 24/7" +date: 2026-03-17 +author: "Squad (Copilot)" +wave: null +tags: [squad, ralph, monitoring, health, state, persistence] +status: published +hero: "Ralph evolved from ephemeral monitor to persistent guardian. Track agent activity 24/7, detect stale sessions, and maintain squad health with continuous state tracking." +--- + +# Persistent Ralph: Monitor Squad Health 24/7 + +> _Ralph now runs continuously with persistent state. Know what your agents are doing, detect problems early, and analyze squad productivity over time._ + +## The Problem + +Ralph was great at snapshots: "Tell me what everyone's working on right now." But what about deeper questions? + +- Which agents go idle the longest before restarting? +- What was the squad's productivity trend this week? +- Did an agent crash or intentionally stop? +- What do we spend most time on: features, bugs, or maintenance? + +Ralph's ephemeral nature made these impossible. Each session died when Ralph stopped, erasing the history. + +The squad needed a **persistent Ralph** that accumulates knowledge across cycles. + +## How It Works + +### Continuous Heartbeat + +Ralph runs on a timer (default: every 5 minutes) via `.squad/schedule.json`: + +```json +{ + "id": "ralph-heartbeat", + "trigger": { "type": "interval", "intervalSeconds": 300 }, + "task": { "type": "script", "command": "squad ralph watch --duration 25s" }, + "providers": ["local-polling", "github-actions"] +} +``` + +This setup ensures: +- **Local development**: Ralph checks work when you run `squad schedule watch` +- **Production**: Ralph runs 24/7 via GitHub Actions cron job + +### Persistent State + +Ralph saves session data to `.squad/.ralph-state.json`: + +```json +{ + "sessions": [ + { + "id": "session-abc123", + "agentName": "copilot-data", + "status": "completed", + "startedAt": "2026-03-17T09:30:00Z", + "endedAt": "2026-03-17T10:15:00Z", + "duration": 2700, + "milestones": ["dependencies analyzed", "refactoring complete"], + "task": "Optimize database queries", + "result": "5 slow queries identified, 2 fixed" + } + ] +} +``` + +History survives: +- Restarts (data is on disk) +- Crashes (last known good state) +- Deployments (state persists across versions) + +### Event Tracking + +Ralph observes agent lifecycle events: + +``` +14:25:00 session:created (copilot-data starts) +14:26:15 agent:milestone "database schema analyzed" +14:28:30 agent:milestone "test suite written" +14:40:00 agent:milestone "performance improved 40%" +14:42:00 session:destroyed (copilot-data finishes) +``` + +These events accumulate into a permanent record. + +## Real-World Scenario + +### Day 1: Enable Persistent Ralph + +```bash +squad schedule init ralph-heartbeat --trigger interval:300 +git commit -m "Enable Ralph persistent monitoring" +git push +``` + +Ralph's heartbeat deploys. Every 5 minutes, GitHub Actions runs `squad ralph watch`. + +### Day 2: Monitor Work + +Ralph observes: +- Agent 1: 45 min session, completed feature +- Agent 2: 10 min session, fixed bug +- Agent 3: 60 min session, refactored tests +- Agent 4: 5 min session, updated docs + +State saved to `.squad/.ralph-state.json`. + +### Day 5: Ask Historical Questions + +```bash +Ralph, show me productivity for the last 3 days +``` + +Ralph queries the persistent state: +``` +Mar 15: 8 sessions, 4 completed (50%), 2 blocked, 2 stale +Mar 16: 12 sessions, 10 completed (83%), 1 blocked, 1 error +Mar 17: 6 sessions (so far), 5 completed (83%), 0 blocked +``` + +Trend: Productivity improving, fewer stale sessions. + +```bash +Ralph, what's taking the most time? +``` + +Ralph aggregates all sessions: +``` +Top Activities (by total time): +1. Writing/updating tests (34%) +2. Refactoring (22%) +3. Documentation (18%) +4. Performance work (15%) +5. Bug fixes (11%) +``` + +## Architecture + +### Three Layers of Ralph + +Ralph now operates at three layers: + +**Layer 1: Event Listener** (always on) +- Subscribes to agent lifecycle events +- Records start, milestones, stop +- Writes to `.squad/.ralph-state.json` + +**Layer 2: Health Monitor** (periodic) +- Runs every 30 seconds +- Checks for stale sessions (no activity > 5 min) +- Checks for hung processes +- Logs warnings and alerts + +**Layer 3: Trend Analyzer** (on-demand) +- Called when you ask questions like "show me productivity" +- Aggregates historical data +- Computes trends and patterns + +All three layers are now fully operational. + +## Configuration + +Customize Ralph in `.squad/config.json`: + +```json +{ + "ralph": { + "healthCheckInterval": 30000, + "staleSessionThreshold": 300000, + "persistenceEnabled": true, + "archiveDaily": true, + "maxHistoryDays": 90 + } +} +``` + +- **healthCheckInterval**: How often to check for stale sessions (default: 30s) +- **staleSessionThreshold**: Mark idle after N milliseconds (default: 5 min) +- **persistenceEnabled**: Save state to disk (default: true) +- **archiveDaily**: Roll over to archive every day (default: true) +- **maxHistoryDays**: Keep history for N days (default: 90 days) + +## Stale Detection + +Ralph automatically flags idle agents: + +``` +Agent: copilot-platform +├─ Last Activity: 10 minutes ago +├─ Status: STALE +└─ Recommendation: Check if hung or waiting for input +``` + +Ralph checks every 30 seconds and logs: +- What was the agent doing last? +- How long has it been idle? +- Is the process still running? +- Suggested next steps + +## Multi-Platform Awareness + +Ralph now adapts to your platform: + +### GitHub Native +```bash +Ralph, show me GitHub Actions run history +``` +Ralph queries: GitHub CI status, PR reviews, action timings + +### Azure DevOps Native +```bash +Ralph, show me pipeline builds +``` +Ralph queries: ADO pipeline status, work item updates, build timings + +### Planner Native +```bash +Ralph, show me Planner task progress +``` +Ralph queries: Task status, plan updates, assignments + +Ralph auto-detects your platform and adapts its monitoring. + +## Use Cases + +### Debug Productivity + +```bash +Ralph, why did we ship 3 fewer features this week? +``` + +Ralph analyzes data: +``` +Work Breakdown This Week: +- Features: 2 (vs. 5 last week) ↓60% +- Tests: 4 (vs. 2 last week) ↑100% +- Bugs: 6 (vs. 3 last week) ↑100% + +Likely cause: Increased test coverage effort + more bugs reported. +``` + +### Optimize Workflows + +```bash +Ralph, what's slowing down our PRs? +``` + +Ralph finds: +``` +Average PR Cycle: 4.2 hours + +Breakdown: +- Author writes PR: 45 min ✓ +- Waiting for review: 2.5 hours ⚠️ (60% of time!) +- Review feedback: 30 min ✓ +- Fixes & re-review: 20 min ✓ +- Merge: 5 min ✓ + +Recommendation: Faster reviewer turnaround = biggest gain. +``` + +### Capacity Planning + +```bash +Ralph, show me utilization this month +``` + +Ralph reports: +``` +Average Sessions per Day: 8 +Average Session Duration: 35 min +Total Productive Hours: 47 hours +Team Capacity (5 agents × 8h): 40 hours + +Utilization: 118% (some overlap/parallelism) +``` + +### Spot Trends + +```bash +Ralph, have we gotten faster at writing tests? +``` + +Ralph shows: +``` +Test Writing Trend (30-day window): +- Week 1: 45 min per test file +- Week 2: 42 min per test file +- Week 3: 38 min per test file ↓ (16% improvement) +- Week 4: 37 min per test file ↓ (staying efficient) + +Conclusion: Better, stable at ~38 min per file. +``` + +## Data Format + +Historical data structure: + +```json +{ + "monitor": { + "startedAt": "2026-03-10T00:00:00Z", + "lastHealthCheck": "2026-03-17T14:30:00Z", + "uptime": 604800, + "status": "healthy" + }, + "sessions": [ + { + "id": "session-123", + "agentName": "copilot-data", + "task": "Refactor user model", + "status": "completed", + "startedAt": "2026-03-17T09:30:00Z", + "endedAt": "2026-03-17T10:15:00Z", + "duration": 2700, + "milestones": [ + { "time": "2026-03-17T09:31:00Z", "label": "schema analyzed" }, + { "time": "2026-03-17T10:00:00Z", "label": "tests written" } + ] + } + ] +} +``` + +## Archival + +By default, Ralph archives weekly: + +``` +.squad/.ralph-archive/ +├─ 2026-03-10-archive.json (week of Mar 3-9) +├─ 2026-03-17-archive.json (week of Mar 10-16) +└─ 2026-03-24-archive.json (week of Mar 17-23) +``` + +Archives are never deleted (until `maxHistoryDays` expires). Query any week: + +```bash +Ralph, show me productivity for week of March 10 +``` + +## See Also + +- [Generic Scheduler](/features/generic-scheduler) — Schedule Ralph's heartbeat +- [Upstream Auto-Sync](/features/upstream-sync) — Ralph monitors sync status +- [Cross-Squad Orchestration](/features/cross-squad-orchestration) — Ralph tracks delegation 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/features/ado-configurable-work-items.md b/docs/features/ado-configurable-work-items.md new file mode 100644 index 000000000..7fdba8a35 --- /dev/null +++ b/docs/features/ado-configurable-work-items.md @@ -0,0 +1,278 @@ +# ADO Configurable Work Items + +**Try this to see available work item types:** +``` +squad init --introspect +``` + +**Try this to configure your work items:** +``` +squad config set workItemType "Scenario" areaPath "MyProject\\Team A" +``` + +**Try this to create a work item in a specific area:** +``` +squad create issue "Add feature X" --areaPath "MyProject\\Frontend" +``` + +Work with any Azure DevOps process template. Squad automatically detects available work item types, area paths, and iterations—no more hardcoded User Stories. + +--- + +## What ADO Configurable Work Items Does + +Work item creation was hardcoded: Squad always created User Stories in a default area. This breaks with custom ADO process templates. Now Squad adapts to your ADO setup: + +1. **Introspect** — Auto-discover available work item types in your project +2. **Configure** — Set default type, area path, and iteration +3. **Create** — Create work items matching your process template +4. **Validate** — Pre-check that your config is valid before using it + +## Quick Start + +### Initialize and Introspect + +When setting up a new squad in Azure DevOps: +```bash +squad init --org contoso --project "My Project" --introspect +``` + +Squad queries the ADO API to find: +- Available work item types (User Story, Bug, Task, Scenario, etc.) +- Area paths in the project +- Iterations/sprints +- Custom fields + +Output: +``` +Azure DevOps Process Template: Scrum + +Available Work Item Types: + - Impediment + - Bug + - Task + - User Story + - Feature + - Epic + +Available Areas: + - My Project + - My Project\Backend Team + - My Project\Frontend Team + +Available Iterations: + - My Project\Sprint 1 + - My Project\Sprint 2 +``` + +### Configure Defaults + +Store your preferences in `.squad/config.json`: + +```bash +squad config set workItemType "Bug" areaPath "My Project\Backend Team" +``` + +Or edit `.squad/config.json` directly: + +```json +{ + "ado": { + "org": "contoso", + "project": "My Project", + "defaultWorkItemType": "Bug", + "areaPath": "My Project\Backend Team", + "iterationPath": "My Project\Sprint 1" + } +} +``` + +### Create Work Items + +Ralph (work monitor) now uses your config: + +```bash +squad ralph scan +``` + +Creates work items with: +- Type from `defaultWorkItemType` (or "User Story" fallback) +- Area from `areaPath` (or project root fallback) +- Iteration from `iterationPath` (optional) + +Override per-item: +```bash +squad create issue "Critical bug" --type Bug --areaPath "My Project\Backend Team" +``` + +## Configuration Reference + +Add to `.squad/config.json`: + +```json +{ + "ado": { + "org": "your-org", + "project": "Your Project Name", + "defaultWorkItemType": "User Story", + "areaPath": "Your Project\Team Name", + "iterationPath": "Your Project\Sprint 1" + } +} +``` + +All fields are optional. Defaults: +- `defaultWorkItemType`: "User Story" +- `areaPath`: Project root +- `iterationPath`: Not set + +### Validation + +Before using a config, validate it: + +```bash +squad config validate +``` + +Output: +``` +✓ Organization: contoso +✓ Project: My Project +✓ Default Work Item Type: Bug (found in available types) +✓ Area Path: My Project\Backend Team (found) +✓ Iteration Path: My Project\Sprint 1 (found) + +Config is valid. Ready to use. +``` + +## How It Works + +### Introspection + +When you run `squad init --introspect`: + +1. Connect to ADO using `az cli` credentials +2. Query the project's process template +3. List available work item types +4. Enumerate area paths +5. List iterations/sprints +6. Save suggestions to `.squad/config.json` + +### Creation + +When creating a work item: + +1. Load config from `.squad/config.json` +2. Resolve `areaPath` to ADO internal ID +3. Resolve `iterationPath` to ADO internal ID +4. Call `az boards work-item create` with all parameters +5. Log the created work item ID + +### Validation + +Before attempting creation: + +1. Check that `defaultWorkItemType` exists in the project +2. Check that `areaPath` exists in the project +3. Check that `iterationPath` exists (if specified) +4. Return validation errors before attempting creation + +## Process Template Support + +Squad works with all ADO process templates: + +### Scrum +- Work item types: Epic, Feature, User Story, Task, Bug, Impediment +- Area paths: Team names +- Iterations: Sprint 1, Sprint 2, etc. + +### Agile +- Work item types: Epic, Feature, User Story, Task, Bug, Issue +- Area paths: Component names +- Iterations: Iteration 1, Iteration 2, etc. + +### CMMI +- Work item types: Epic, Feature, Requirement, Task, Bug, Review, etc. +- Area paths: Department/Team structure +- Iterations: Phase 1, Phase 2, etc. + +### Custom Templates +- Introspect to see what's available +- Configure Squad to match your template + +## Real-World Example + +### Multi-Team Setup + +Your org has three teams, each with their own squad: + +**Backend Squad** (Scrum process): +```json +{ + "ado": { + "org": "acme", + "project": "Platform", + "defaultWorkItemType": "User Story", + "areaPath": "Platform\Backend", + "iterationPath": "Platform\Sprint 1" + } +} +``` + +**Frontend Squad** (Agile process, custom): +```json +{ + "ado": { + "org": "acme", + "project": "Platform", + "defaultWorkItemType": "Story", + "areaPath": "Platform\Frontend" + } +} +``` + +**QA Squad** (Bug-focused): +```json +{ + "ado": { + "org": "acme", + "project": "Platform", + "defaultWorkItemType": "Bug", + "areaPath": "Platform\QA" + } +} +``` + +Each squad creates work items in their native format and area. + +## Ralph Integration + +Ralph (work monitor) uses your ADO config to create and track work: + +```bash +squad ralph scan --ado +``` + +Ralph now creates work items using: +- Your configured `defaultWorkItemType` +- Your configured `areaPath` +- Your configured `iterationPath` (if set) + +Example: Backend squad finds an issue → creates Bug in "Platform\Backend" area + +## Fallback Behavior + +If config is not set or validation fails: + +1. Try to use config values +2. If missing, fall back to: + - Work item type: "User Story" + - Area: Project root + - Iteration: None +3. Log warnings if fallback occurs + +## See Also + +- [Persistent Ralph](/features/persistent-ralph) — Monitor work with your ADO config +- [Cross-Squad Orchestration](/features/cross-squad-orchestration) — Delegate work across squads +- [Generic Scheduler](/features/generic-scheduler) — Run ADO operations on schedule diff --git a/docs/features/cross-squad-orchestration.md b/docs/features/cross-squad-orchestration.md new file mode 100644 index 000000000..8be7d1401 --- /dev/null +++ b/docs/features/cross-squad-orchestration.md @@ -0,0 +1,200 @@ +# Cross-Squad Orchestration + +**Try this to discover known squads:** +``` +squad discover +``` + +**Try this to delegate work:** +``` +squad delegate backend-squad "Optimize the API response time" +``` + +**Try this to see squad details:** +``` +squad discover backend-squad +``` + +Cross-squad orchestration lets you discover other squads' capabilities and delegate work directly to them. Build a mesh of specialized squads that work together. + +--- + +## What Cross-Squad Orchestration Does + +Cross-squad orchestration enables squads to **discover each other** and **delegate work**. Instead of work bouncing between teams via email, or squads working in isolation, they form a connected mesh: + +1. **Discover** — Find known squads and their capabilities +2. **Understand** — See what work types each squad accepts +3. **Delegate** — Create issues directly in another squad with context +4. **Route** — Issues arrive with proper labels and metadata + +## Quick Start + +### Discover Other Squads + +List all discoverable squads in your network: +```bash +squad discover +``` + +Output: +``` +Known Squads: + backend-squad (github.com/org/backend-squad) + Capabilities: api, database, performance + Contact: @backend-team + Accepts: issues, pull-requests + + frontend-squad (github.com/org/frontend-squad) + Capabilities: ui, ux, accessibility + Contact: @frontend-team + Accepts: issues, pull-requests + + infra-squad (github.com/org/infra-squad) + Capabilities: kubernetes, terraform, ci-cd + Contact: @infra-team + Accepts: issues +``` + +Get details about one squad: +```bash +squad discover backend-squad +``` + +### Delegate Work + +Create an issue in another squad: +```bash +squad delegate backend-squad "Implement caching for user profiles API endpoint" +``` + +The issue is created in backend-squad's repository with: +- Proper labels (automatically applied based on squad manifest) +- Cross-squad metadata in the issue body +- Link back to your squad +- Assignment to the squad's triage team + +Provide more context in a file: +```bash +squad delegate infra-squad --file deployment-request.md +``` + +### Remove an Upstream + +Stop tracking a squad: +```bash +squad delegate remove backend-squad +``` + +## Configuration + +Squads publish their capabilities via `.squad/manifest.json`: + +```json +{ + "name": "backend-squad", + "repo": "github.com/org/backend-squad", + "description": "API and database services", + "capabilities": [ + "api", + "database", + "performance", + "caching" + ], + "accepts": [ + "issues", + "pull-requests" + ], + "contact": { + "team": "Backend Engineering", + "labels": ["squad:backend", "needs-review"] + } +} +``` + +- **name**: Unique squad identifier +- **repo**: GitHub repository URL +- **description**: What the squad does +- **capabilities**: Skills and services offered +- **accepts**: What work types the squad will take on +- **contact**: How to reach them (labels, team mentions) + +## How Discovery Works + +Discovery reads upstream squad manifests: + +1. Find `.squad/upstream.json` in your squad +2. For each upstream, fetch `.squad/manifest.json` +3. Build a local index of known squads +4. Cache the index locally in `.squad/.discovery-cache.json` + +Discovery is **read-only**—it doesn't modify other squads. + +## Use Cases + +### Multi-Team Organization + +- **Platform Squad**: Infrastructure, databases, deployments +- **Feature Squad A**: Mobile and API clients +- **Feature Squad B**: Web frontend and analytics +- **Infra Squad**: CI/CD, monitoring, on-call + +Teams discover each other's capabilities and delegate work instead of context-switching. + +### Distributed Org + +- Multiple orgs, each with their own squads +- Cross-org upstreams link squads (with permission) +- Feature team can delegate testing to central QA squad +- QA squad can delegate infrastructure to platform team + +### Specialized Service Squads + +- DevOps squad publishes "kubernetes", "terraform", "monitoring" capabilities +- Any team discovering DevOps can delegate infrastructure tasks +- No need to find the right person—just find the right squad + +## Manifest Best Practices + +### Be Descriptive + +```json +{ + "capabilities": [ + "rest-api", + "graphql", + "websockets", + "performance-optimization" + ] +} +``` + +Not just `["backend"]` — be specific about what you can do. + +### Label for Routing + +```json +{ + "contact": { + "labels": ["squad:backend", "epic:api", "priority:high"] + } +} +``` + +Labels help delegates find the right backlog and priority. + +### Document Acceptance Criteria + +```json +{ + "description": "API and database services. We accept issues that involve REST/GraphQL APIs, query optimization, and data modeling." +} +``` + +Delegates know whether their work fits. + +## See Also + +- [Upstream Auto-Sync](/features/upstream-sync) — Keep squads in sync automatically +- [Persistent Ralph](/features/persistent-ralph) — Track all squad activity +- [Generic Scheduler](/features/generic-scheduler) — Schedule cross-squad workflows diff --git a/docs/features/generic-scheduler.md b/docs/features/generic-scheduler.md new file mode 100644 index 000000000..f7095462e --- /dev/null +++ b/docs/features/generic-scheduler.md @@ -0,0 +1,326 @@ +# Generic Scheduler + +**Try this to see all scheduled tasks:** +``` +squad schedule list +``` + +**Try this to check next run times:** +``` +squad schedule status +``` + +**Try this to trigger a task manually:** +``` +squad schedule run ralph-heartbeat +``` + +The generic scheduler unifies cron jobs, polling loops, and manual triggers. Define all recurring squad tasks in one place and let Squad orchestrate them. + +--- + +## What the Generic Scheduler Does + +The generic scheduler gives squads a **unified way to schedule and run recurring tasks**: + +1. **Define** tasks in `.squad/schedule.json` (cron, interval, event-driven, startup) +2. **Trigger** locally via `squad schedule run` or automatically via polling +3. **Monitor** with `squad schedule status` to see run history and next run times +4. **Recover** from failures with configurable retry and backoff +5. **Scale** to GitHub Actions for headless/CI environments + +No more scattered cron jobs, polling scripts, or manual triggers. + +## Quick Start + +### Initialize a Schedule + +Create a default `.squad/schedule.json`: +```bash +squad schedule init +``` + +This creates: +```json +{ + "schedules": [ + { + "id": "ralph-heartbeat", + "name": "Ralph Work Monitor", + "enabled": true, + "trigger": { "type": "interval", "intervalSeconds": 300 }, + "task": { "type": "script", "command": "squad ralph watch --duration 30s" }, + "providers": ["local-polling"], + "retry": { "maxRetries": 1, "backoffSeconds": 5 } + } + ] +} +``` + +### List All Schedules + +```bash +squad schedule list +``` + +Output: +``` +ID Name Trigger Status +ralph-heartbeat Ralph Work Monitor Every 5min Enabled +upstream-sync Upstream Sync Every 6h Enabled +ci-daily-report Daily CI Report Mon-Fri 8am Enabled +``` + +### Check Status + +```bash +squad schedule status +``` + +Output: +``` +ralph-heartbeat + Last Run: 2026-03-17 14:25:30 (Success) + Next Run: 2026-03-17 14:30:30 (in 4min) + +upstream-sync + Last Run: 2026-03-17 12:00:00 (Success) + Next Run: 2026-03-17 18:00:00 (in 4h) +``` + +### Run Manually + +Trigger a task immediately: +```bash +squad schedule run ralph-heartbeat +``` + +## Schedule Configuration + +The schedule manifest lives in `.squad/schedule.json`: + +```json +{ + "schedules": [ + { + "id": "unique-id", + "name": "Human-readable name", + "description": "What this task does", + "enabled": true, + "trigger": { ... }, + "task": { ... }, + "providers": ["local-polling"], + "retry": { "maxRetries": 2, "backoffSeconds": 5 }, + "tags": ["monitoring", "core"] + } + ] +} +``` + +### Trigger Types + +#### Interval +Run every N seconds: +```json +{ "type": "interval", "intervalSeconds": 300 } +``` + +#### Cron +Use standard cron syntax: +```json +{ "type": "cron", "expression": "0 8 * * MON-FRI" } +``` + +#### Event +Run when something happens: +```json +{ "type": "event", "eventName": "session:complete" } +``` + +#### Startup +Run once when squad initializes: +```json +{ "type": "startup" } +``` + +### Task Types + +#### Script +Run a shell command: +```json +{ "type": "script", "command": "squad upstream sync" } +``` + +#### Workflow +Trigger a GitHub Actions workflow: +```json +{ "type": "workflow", "ref": ".github/workflows/daily-report.yml" } +``` + +#### Copilot +Run a Copilot agent task: +```json +{ "type": "copilot", "agent": "ralph", "prompt": "check work queue" } +``` + +#### Webhook +POST to a URL: +```json +{ "type": "webhook", "url": "https://example.com/hooks/squad-task" } +``` + +### Providers + +#### Local Polling +Run in-process when `squad` is running: +```json +{ "providers": ["local-polling"] } +``` + +Use this for development and testing. Runs until you stop the squad CLI. + +#### GitHub Actions +Automatically generate and trigger GitHub Actions workflows: +```json +{ "providers": ["github-actions"] } +``` + +Use this for production. Squad generates `.github/workflows/schedule-{id}.yml` and GitHub runs it on schedule. + +## Real-World Example + +### Multi-Task Schedule + +```json +{ + "schedules": [ + { + "id": "ralph-monitor", + "name": "Ralph Work Monitor", + "trigger": { "type": "interval", "intervalSeconds": 300 }, + "task": { "type": "script", "command": "squad ralph watch --duration 25s" }, + "providers": ["local-polling", "github-actions"], + "retry": { "maxRetries": 2, "backoffSeconds": 10 } + }, + { + "id": "upstream-sync", + "name": "Upstream Sync", + "trigger": { "type": "cron", "expression": "0 */6 * * *" }, + "task": { "type": "script", "command": "squad upstream sync --auto-pr" }, + "providers": ["github-actions"], + "retry": { "maxRetries": 1, "backoffSeconds": 30 } + }, + { + "id": "daily-report", + "name": "Daily Status Report", + "trigger": { "type": "cron", "expression": "0 9 * * MON-FRI" }, + "task": { "type": "workflow", "ref": ".github/workflows/daily-report.yml" }, + "providers": ["github-actions"] + } + ] +} +``` + +This schedule: +- Monitors work every 5 minutes (local + GHA) +- Syncs upstreams every 6 hours (GHA only, no local polling) +- Generates a daily report on weekday mornings (GHA only) + +## Local vs. GitHub Actions + +### Local Polling (`squad schedule`) + +Run while working locally: +```bash +cd my-squad +squad schedule watch +``` + +The scheduler runs in your terminal until you exit. Tasks execute in-process. Perfect for development. + +### GitHub Actions + +For production and headless environments, Squad generates workflows: + +```bash +squad schedule init-ci +``` + +This creates `.github/workflows/squad-schedule-*.yml` files. GitHub Actions runs them on your schedule. + +Advantages: +- Runs 24/7 (no local machine needed) +- Logs available in GitHub UI +- Built-in error notifications +- No setup beyond git push + +## State & History + +Squad maintains schedule state in `.squad/.schedule-state.json`: + +```json +{ + "ralph-monitor": { + "lastRun": "2026-03-17T14:25:30Z", + "lastStatus": "success", + "lastOutput": "10 issues found, 3 stale", + "nextRun": "2026-03-17T14:30:30Z", + "runCount": 1847, + "failCount": 3 + } +} +``` + +This is auto-managed. You can inspect it but shouldn't edit it directly. + +## Use Cases + +### Monitoring Loop +Monitor work queue every 5 minutes: +```bash +squad schedule init ralph-monitor +``` + +### Hourly Syncs +Keep multiple squads synchronized: +```bash +squad upstream sync --interval hourly +``` + +### Daily Reports +Generate daily team status reports: +```bash +squad schedule run daily-report +``` + +### Event Hooks +Trigger on session complete: +```bash +squad schedule new downstream-notify --event session:complete +``` + +## Error Handling + +Schedules include retry logic: + +```json +{ + "retry": { + "maxRetries": 2, + "backoffSeconds": 5 + } +} +``` + +If a task fails: +1. Wait 5 seconds +2. Retry (first attempt) +3. Wait 10 seconds (exponential backoff) +4. Retry (second attempt) +5. If still failing, log error and skip until next trigger + +## See Also + +- [Upstream Auto-Sync](/features/upstream-sync) — Use scheduler to sync automatically +- [Persistent Ralph](/features/persistent-ralph) — Monitor squad work continuously +- [Cross-Squad Orchestration](/features/cross-squad-orchestration) — Delegate across squads diff --git a/docs/features/persistent-ralph.md b/docs/features/persistent-ralph.md new file mode 100644 index 000000000..7abc82a86 --- /dev/null +++ b/docs/features/persistent-ralph.md @@ -0,0 +1,343 @@ +# Persistent Ralph + +**Try this to see what agents are working on:** +``` +Ralph, show me current work status +``` + +**Try this to check for stale sessions:** +``` +Ralph, who's been idle the longest? +``` + +**Try this to get a summary:** +``` +Ralph, summarize squad activity in the last hour +``` + +Ralph now runs continuously with persistent state. Track agent activity trends, detect stuck processes, and maintain squad health 24/7. + +--- + +## What Persistent Ralph Does + +Ralph evolved from an ephemeral monitor to a **persistent, stateful squad guardian**: + +1. **Continuous Monitoring** — Ralph runs 24/7 via GitHub Actions heartbeat +2. **State Persistence** — Session data survives restarts and crashes +3. **Activity Tracking** — Know what each agent is working on, when they start/stop +4. **Stale Detection** — Automatically flag idle or hung processes +5. **Trend Analysis** — Understand squad productivity over time + +## Quick Start + +### Enable Persistent Monitoring + +Ralph runs automatically once enabled. To check status: + +```bash +Ralph, show squad status +``` + +Ralph reports: +- Active agents and their tasks +- Last activity timestamp for each +- Issues or blockers detected +- Recommended next actions + +### Add Heartbeat Cron + +Enable Ralph's background heartbeat: + +```bash +squad schedule init ralph-heartbeat --trigger interval:300 +``` + +This adds a 5-minute polling cycle to `.squad/schedule.json`. Ralph checks: +- All active sessions +- Agent health +- Pending work +- Blocker status + +Commit the schedule: +```bash +git add .squad/schedule.json +git commit -m "Enable Ralph heartbeat" +``` + +### Check Session History + +See what agents have done: + +```bash +Ralph, show me sessions from the last 24 hours +``` + +Output: +``` +Session 1 (9:30 AM - 10:15 AM, 45 min) + Agent: copilot-data + Task: Refactor user model + Status: Completed + PRs: 1 (merged) + +Session 2 (10:20 AM - still running, 15 min) + Agent: copilot-platform + Task: Add caching layer + Status: In Progress + Blockers: Waiting for review + +Session 3 (8:30 AM - 8:45 AM, 15 min) + Agent: copilot-docs + Task: Update API docs + Status: Completed + Changes: 12 files +``` + +## Configuration + +Ralph's persistent state is stored in `.squad/.ralph-state.json`: + +```json +{ + "monitor": { + "healthCheckInterval": 30000, + "staleSessionThreshold": 300000, + "lastCheck": "2026-03-17T14:30:00Z", + "status": "healthy" + }, + "sessions": [ + { + "id": "session-123", + "agentName": "copilot-data", + "status": "working", + "startedAt": "2026-03-17T14:25:00Z", + "lastActivity": "2026-03-17T14:29:50Z", + "currentTask": "Optimize database queries", + "milestones": ["analyzed schema", "drafted plan"], + "output": "Found 3 expensive queries..." + } + ] +} +``` + +Add to `.squad/config.json` to customize: + +```json +{ + "ralph": { + "healthCheckInterval": 30000, + "staleSessionThreshold": 300000, + "persistenceEnabled": true + } +} +``` + +- **healthCheckInterval**: Check health every N ms (default: 30 seconds) +- **staleSessionThreshold**: Mark session stale after N ms idle (default: 5 minutes) +- **persistenceEnabled**: Save state to disk (default: true) + +## How It Works + +### Lifecycle + +1. **Session Starts** → Ralph registers the session, records start time +2. **Agent Works** → Ralph observes milestones, progress checkpoints +3. **Agent Idles** → After 5 minutes of no activity, Ralph flags as "idle" +4. **Session Ends** → Ralph archives the session with final status +5. **Trend Analysis** → Ralph aggregates historical data + +### Event Tracking + +Ralph subscribes to agent lifecycle events: + +- `session:created` — Agent started working +- `session:milestone` — Agent reached a checkpoint (e.g., "files analyzed", "tests passing") +- `session:error` — Agent encountered an error +- `session:destroyed` — Agent finished or crashed + +Example session with milestones: +``` +Session: squad-copilot-data (14:25 - 14:42) +├─ 14:25:00 session:created +├─ 14:26:15 session:milestone "dependencies analyzed" +├─ 14:28:30 session:milestone "tests written" +├─ 14:30:00 session:milestone "refactoring started" +├─ 14:40:45 session:milestone "all tests passing" +└─ 14:42:00 session:destroyed (success) +``` + +### Stale Detection + +Ralph tracks inactivity: + +``` +Session: squad-copilot-platform (10:00 - still running) +├─ Last activity: 11:45 (25 minutes ago) +├─ Status: STALE (no activity since 11:30 threshold) +├─ Likely causes: hung process, waiting for input, network issue +└─ Recommendation: Check logs, consider restart +``` + +## Health Checks + +Ralph performs periodic health checks every 30 seconds: + +```bash +Ralph, show health status +``` + +Output: +``` +Ralph Health Status (as of 14:35:00) + +Monitor: Healthy +├─ Uptime: 2h 15m +├─ Last Check: 30 seconds ago +└─ Issues: None + +Active Sessions: 3 +├─ copilot-data (30m) - Working on user model +├─ copilot-platform (5m) - Starting caching task +└─ copilot-docs (2m) - Updating API docs + +Idle Sessions: 1 +├─ copilot-test (45m idle) - STALE - Consider restart + +Completed Sessions (today): 12 +├─ Success: 11 +└─ Error: 1 +``` + +## Persistent Heartbeat + +Ralph's background heartbeat is defined in `.squad/schedule.json`: + +```json +{ + "id": "ralph-heartbeat", + "name": "Ralph Health Monitor", + "trigger": { "type": "interval", "intervalSeconds": 300 }, + "task": { "type": "script", "command": "squad ralph watch --duration 25s" }, + "providers": ["local-polling", "github-actions"], + "retry": { "maxRetries": 1, "backoffSeconds": 10 } +} +``` + +This runs: +- **Locally**: Every 5 minutes while you're working (via `squad schedule watch`) +- **In GitHub Actions**: Every 5 minutes 24/7 (via generated workflow) + +## Use Cases + +### Detect Hung Agents + +Ralph flags an agent that hasn't produced output in 5 minutes: + +``` +Session: copilot-linter (14:00 - still running) +└─ STALE for 15 minutes + Recommendation: Check CPU, kill process, and restart +``` + +### Trend Analysis + +See what the squad was productive on: + +```bash +Ralph, summarize productivity for week +``` + +``` +Week of Mar 10-16: + +Total Sessions: 45 +Success Rate: 96% +Avg Duration: 28 min +Most Productive Day: Thursday (9 sessions) + +Top Tasks: +1. Writing tests (18%) +2. Refactoring (22%) +3. Docs (12%) +4. Performance (10%) +5. Bugs (5%) + +Trends: +- Tests passing rate: 95% (↑ from 88%) +- Avg PR size: 180 lines (stable) +- Time to merge: 2.1h (↓ from 3.2h) +``` + +### Squad Health Dashboard + +As part of Ralph's monitoring: + +```bash +Ralph, show squad health +``` + +``` +Squad Health: 92% (Excellent) + +Active Contributors: 4 +├─ copilot-data: 35% productivity +├─ copilot-platform: 28% +├─ copilot-docs: 22% +└─ copilot-infra: 15% + +Blockers: 2 +├─ PR #142 (waiting 6h for review) +└─ Issue #89 (stale, assigned to nobody) + +Work Queue: +├─ Ready: 8 issues +├─ In Progress: 5 issues +├─ Blocked: 2 issues +``` + +## Data Retention + +Ralph persists state to: +- `.squad/.ralph-state.json` — Current state and session history +- `.squad/.ralph-archive/` — Historical snapshots (weekly) + +Archive format: +``` +.squad/.ralph-archive/ +├─ 2026-03-10.json (week of Mar 3-9) +├─ 2026-03-17.json (week of Mar 10-16) +└─ 2026-03-24.json (week of Mar 17-23) +``` + +View historical data: +```bash +Ralph, show activity for week of March 10 +``` + +## Multi-Platform Support + +Ralph now detects the platform and adapts: + +### GitHub +- Pulls CI status from GitHub Actions +- Monitors PR reviews and comments +- Integrates with GitHub Issues + +### Azure DevOps +- Tracks work item status +- Monitors pipeline builds +- Integrates with ADO backlog + +### Planner +- Tracks task progress +- Monitors plan status +- Integrates with Planner tasks + +Ralph adjusts its monitoring based on what platform the squad uses. + +## See Also + +- [Generic Scheduler](/features/generic-scheduler) — Schedule Ralph's heartbeat +- [Upstream Auto-Sync](/features/upstream-sync) — Ralph can monitor sync status +- [Cross-Squad Orchestration](/features/cross-squad-orchestration) — Ralph tracks delegation status diff --git a/docs/features/upstream-inheritance.md b/docs/features/upstream-inheritance.md deleted file mode 100644 index 9e769da48..000000000 --- a/docs/features/upstream-inheritance.md +++ /dev/null @@ -1,725 +0,0 @@ -# Upstream Inheritance - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -Upstream inheritance allows you to declare external Squad sources—from other repositories, local directories, or exports—and automatically inherit their context (skills, decisions, wisdom, casting policy, routing) at session start. This enables knowledge sharing across teams, organizations, and projects without duplicating Squad configuration. - -## Why Upstream Inheritance Matters - -When you have multiple teams using Squad in an organization, you need a way to share common practices, agent definitions, and decision-making frameworks. Upstream inheritance solves this without creating dependency trees: - -- **Org-level guidance** flows down to team repos and individual projects -- **Platform team standards** propagate to all consuming teams -- **Shared methodologies** scale across client projects or service offerings -- **Domain models** stay consistent across multiple services - -Instead of copying configuration, you point to it—and at session start, the coordinator reads all declared upstreams and makes their context available to every spawned agent. - -## Core Concepts - -### Three Source Types - -Upstreams can come from three places: - -| Type | Example | Use Case | -|------|---------|----------| -| **local** | `../org-practices/.squad/` | Sibling repo on disk, shared drive, monorepo package | -| **git** | `https://github.com/acme/platform-squad.git` | Public org repository or private team repo (with proper credentials) | -| **export** | `./exports/squad-export.json` | Snapshot for offline use or version pinning | - -### Hierarchy and Resolution - -Squad follows a **closest-wins** principle: - -``` -Org-level upstream - ↓ -Team-level upstream - ↓ -Repository config (local upstream.json) - ↓ -My agent instance -``` - -The resolver reads upstreams in the order they appear in `upstream.json`, and **later entries override earlier ones** for the same content type. This means you can layer upstreams from org → team → repo, with each level adding or overriding as needed. - -### What Gets Inherited - -When you add an upstream, the coordinator reads all of these from its `.squad/` directory: - -- **Skills** — all `.squad/skills/*/SKILL.md` files -- **Decisions** — `.squad/decisions.md` -- **Wisdom** — `.squad/identity/wisdom.md` -- **Casting Policy** — `.squad/casting/policy.json` -- **Routing** — `.squad/routing.md` - -If a resource doesn't exist in an upstream, it's skipped (no error). This allows upstreams to provide partial context. - -## Getting Started - -### Quick Start: Local Upstream - -If you have a sibling repository with Squad configuration: - -```bash -# Add a local upstream from a nearby directory -squad upstream add ../org-practices/.squad - -# The coordinator infers the name: "org-practices" -``` - -Check it: - -```bash -squad upstream list -# Output: -# org-practices → local: /path/to/org-practices/.squad (never synced) -``` - -The coordinator reads from this path **live** at session start—no sync needed. - -### Quick Start: Git Upstream - -For a remote repository: - -```bash -# Add from a public GitHub repo -squad upstream add https://github.com/acme/platform-squad.git --name platform - -# Or specify a branch -squad upstream add https://github.com/acme/platform-squad.git --name platform --ref develop -``` - -On first add, Squad clones the repo to `.squad/_upstream_repos/platform`. Keep this directory in `.gitignore`: - -```bash -# Already done by squad upstream add -cat .gitignore -# .squad/_upstream_repos/ -``` - -Update it later: - -```bash -squad upstream sync platform -``` - -Or sync all: - -```bash -squad upstream sync -``` - -### Quick Start: Export Snapshot - -For offline or pinned versions: - -```bash -# Export an existing Squad config -squad export-config --output ./exports/snapshot.json - -# Add it as an upstream -squad upstream add ./exports/snapshot.json --name snapshot -``` - -## CLI Reference - -### `squad upstream add ` - -Add a new upstream source. - -**Signature:** -``` -squad upstream add [--name ] [--ref ] -``` - -**Arguments:** -- `` — File path, git URL, or export JSON file. Squad auto-detects the type. - -**Options:** -- `--name ` — Display name (optional; defaults to repo/dir name) -- `--ref ` — Git branch/tag (only for git sources; defaults to `main`) - -**Examples:** - -Local directory: -```bash -squad upstream add ../shared-squad --name shared -``` - -Git repository: -```bash -squad upstream add https://github.com/acme/platform-squad.git --name platform --ref main -``` - -Export file: -```bash -squad upstream add ./exports/org-snapshot.json --name org-snapshot -``` - -**What happens:** -- Reads `upstream.json` from `.squad/` -- Detects source type (local, git, export) -- For git sources: auto-clones to `.squad/_upstream_repos/{name}` -- Adds entry to `.squad/upstream.json` -- For local/export: coordinator reads live at session start (no sync needed) - -### `squad upstream remove ` - -Remove an upstream by name. - -**Signature:** -``` -squad upstream remove -``` - -**Examples:** -```bash -squad upstream remove platform -``` - -**What happens:** -- Removes entry from `.squad/upstream.json` -- Deletes cached clone from `.squad/_upstream_repos/{name}` if it exists - -### `squad upstream list` - -Show all configured upstreams. - -**Signature:** -``` -squad upstream list -``` - -**Output example:** -``` -Configured upstreams: - - platform → git: https://github.com/acme/platform-squad.git (ref: main) (synced 2026-02-22) - shared → local: /home/alice/shared-squad (never synced) - snapshot → export: ./exports/org-snapshot.json (synced 2026-02-22) -``` - -### `squad upstream sync [name]` - -Update cached clones for git upstreams, or validate paths for local/export upstreams. - -**Signature:** -``` -squad upstream sync [name] -``` - -**Examples:** - -Sync all: -```bash -squad upstream sync -``` - -Sync one: -```bash -squad upstream sync platform -``` - -**What happens:** -- For **git** sources: `git pull --ff-only` on the cached clone, or re-clones if needed -- For **local** sources: validates that the path exists -- For **export** sources: validates that the file exists -- Updates `last_synced` timestamp in `upstream.json` - -## SDK API Reference - -The upstream module provides resolver functions for programmatic use. - -### Types - -#### `UpstreamType` - -```typescript -type UpstreamType = 'local' | 'git' | 'export'; -``` - -#### `UpstreamSource` - -A declared upstream from `upstream.json`: - -```typescript -interface UpstreamSource { - name: string; // Display name (e.g., "platform") - type: UpstreamType; // How to access it - source: string; // Path, URL, or export file location - ref?: string; // Git ref (only for type: "git") - added_at: string; // ISO timestamp - last_synced: string | null; // Last successful sync -} -``` - -#### `UpstreamConfig` - -The `upstream.json` file format: - -```typescript -interface UpstreamConfig { - upstreams: UpstreamSource[]; -} -``` - -#### `ResolvedUpstream` - -Resolved content from a single upstream: - -```typescript -interface ResolvedUpstream { - name: string; - type: UpstreamType; - skills: Array<{ name: string; content: string }>; - decisions: string | null; - wisdom: string | null; - castingPolicy: Record | null; - routing: string | null; -} -``` - -#### `UpstreamResolution` - -Result of resolving all upstreams: - -```typescript -interface UpstreamResolution { - upstreams: ResolvedUpstream[]; -} -``` - -### Functions - -#### `readUpstreamConfig(squadDir: string): UpstreamConfig | null` - -Read and parse `upstream.json` from a squad directory. - -**Returns:** `null` if file doesn't exist or is invalid. - -**Example:** -```typescript -import { readUpstreamConfig } from '@bradygaster/squad-sdk'; - -const config = readUpstreamConfig('.squad'); -if (config) { - console.log(`Found ${config.upstreams.length} upstreams`); -} -``` - -#### `resolveUpstreams(squadDir: string): UpstreamResolution | null` - -Resolve all upstream sources declared in `upstream.json`. - -For each upstream: -- **local**: reads directly from the source's `.squad/` -- **git**: reads from `.squad/_upstream_repos/{name}/` (must be cloned first) -- **export**: reads from the JSON file - -**Returns:** `null` if no `upstream.json` exists. If a source can't be reached, that upstream is included with empty content (no error thrown). - -**Example:** -```typescript -import { resolveUpstreams } from '@bradygaster/squad-sdk'; - -const resolution = resolveUpstreams('.squad'); -if (resolution) { - for (const upstream of resolution.upstreams) { - console.log(`${upstream.name}: ${upstream.skills.length} skills`); - } -} -``` - -#### `buildInheritedContextBlock(resolution: UpstreamResolution | null): string` - -Build a text block summarizing inherited context (for agent prompts). - -**Returns:** Empty string if no resolution or upstreams. - -**Example output:** -``` -INHERITED CONTEXT: - platform: skills (3), decisions ✓, casting ✓ - shared: skills (5), routing ✓ - snapshot: (empty) -``` - -**Usage:** The coordinator includes this in agent spawn prompts to signal what context is available. - -#### `buildSessionDisplay(resolution: UpstreamResolution | null): string` - -Build a user-facing display for session start greeting. - -**Returns:** Empty string if no resolution or upstreams. - -**Example output:** -``` -📡 Inherited context: - platform (git) — 3 skills, decisions, casting - shared (local) — 5 skills, routing - ⚠️ snapshot (export) — source not reachable -``` - -**Usage:** Shown in the session greeting to confirm what upstreams are available. - -## End-to-End Scenarios - -### Scenario 1: Platform Team at Scale - -**Setting:** Your organization has a platform team that defines shared agent definitions, decisions, and casting policy for all product teams. - -**Structure:** -``` -acme/ - platform-squad (platform team repo) - .squad/ - decisions.md (org-level decisions) - casting/policy.json (standard casting) - skills/ - platform-engineer/SKILL.md - backend-engineer/SKILL.md - product-a (product team repo) - .squad/ - upstream.json - [other files] - product-b (product team repo) - .squad/ - upstream.json - [other files] -``` - -**Setup in product-a:** - -```bash -cd product-a - -# Add platform team's Squad as upstream -squad upstream add https://github.com/acme/platform-squad.git \ - --name platform \ - --ref main - -# Optionally add product-specific decisions -# (platform decisions are already inherited) -``` - -**What happens at session start:** -1. Coordinator reads `.squad/upstream.json` in product-a -2. Resolves `platform` → clones/pulls from GitHub -3. Loads platform's decisions, casting policy, and skills -4. When an agent spawns, it has access to platform's casting rules and decision framework -5. Product team can override by adding their own skills or decisions - -**Benefit:** The platform team updates their practices in one place; all product teams see the changes at their next session start (after `squad upstream sync`). - -### Scenario 2: Open-Source Framework with Community Plugins - -**Setting:** You maintain an open-source framework. Community members contribute agent skills and methodologies. You want them to inherit your framework's core practices without forking. - -**Structure:** -``` -acme-framework (public repo) - .squad/ - decisions.md (framework principles) - skills/ - framework-engineer/SKILL.md - wisdom.md (philosophy) - routing.md (traffic rules) - -community-plugin-a (contributor repo) - .squad/ - upstream.json (points to acme-framework) - skills/ - plugin-specialization/SKILL.md - [other files] - -community-plugin-b (contributor repo) - .squad/ - upstream.json (points to acme-framework) - skills/ - plugin-other/SKILL.md - [other files] -``` - -**Setup in community-plugin-a:** - -```bash -squad upstream add https://github.com/acme/acme-framework.git \ - --name framework -``` - -**What happens:** -1. Plugin developers inherit framework's decisions, wisdom, and core skills -2. Their own skills layer on top -3. When the framework publishes new principles, plugins see them at next sync -4. Plugins can add or override routing without touching the framework - -**Benefit:** Framework governance scales across a community; contributors stay aligned without central control. - -### Scenario 3: Consultancy Methodology Across Client Projects - -**Setting:** You're a consultancy. All client projects should follow your engagement methodology (decisions, casting, methodologies). Each project has unique domain skills. - -**Structure:** -``` -consultancy-methodology (internal repo) - .squad/ - decisions.md (client engagement decision framework) - casting/policy.json (role definitions) - wisdom.md (consulting philosophy) - routing.md (internal routing rules) - -client-a-project (client repo) - .squad/ - upstream.json (points to methodology) - skills/ - client-a-domain-expert/SKILL.md - [other files] - -client-b-project (client repo) - .squad/ - upstream.json (points to methodology) - skills/ - client-b-domain-expert/SKILL.md - [other files] -``` - -**Setup in client-a-project:** - -```bash -squad upstream add https://github.internal/consultancy/methodology.git \ - --name consultancy \ - --ref main -``` - -(Or use SSH/PAT for private repos.) - -**What happens:** -1. Every agent spawned in the client project inherits consultancy's methodology -2. Client-specific skills (domain expertise) are layered on top -3. Consultancy updates methodology; all active projects pull at next sync -4. Each client project remains independent (no shared git history) - -**Benefit:** Quality control at scale; consistent methodology; easy knowledge transfer. - -### Scenario 4: Multi-Team Shared Domain Model - -**Setting:** Three teams work on different services that share a domain model (e.g., user, order, payment). You want a single source of truth for how to work with that model. - -**Structure:** -``` -shared-domain (shared repo, not a full product) - .squad/ - skills/ - domain-modeler/SKILL.md (DDD practices) - database-engineer/SKILL.md (schema design) - decisions.md (data governance) - routing.md (domain event routing) - -user-service (team repo) - .squad/ - upstream.json (points to shared-domain) - [business logic] - -order-service (team repo) - .squad/ - upstream.json (points to shared-domain) - [business logic] - -payment-service (team repo) - .squad/ - upstream.json (points to shared-domain) - [business logic] -``` - -**Setup in user-service:** - -```bash -squad upstream add https://github.com/acme/shared-domain.git --name domain -``` - -**What happens:** -1. All agents spawned across the three services have access to shared domain skills -2. If domain conventions change, the shared-domain repo is updated once -3. Each team pulls the change independently -4. Services stay decoupled (no cross-repo deployments) - -**Benefit:** DDD governance; single source of truth; isolation with consistency. - -### Scenario 5: Post-Acquisition Engineering Convergence - -**Setting:** After acquiring another company, you need to converge engineering practices across two organizations. They have different frameworks, but you want a unified way forward without forcing a rewrite. - -**Structure:** -``` -acme-unified-practices (new shared repo) - .squad/ - decisions.md (merged decision framework) - casting/policy.json (unified roles) - skills/ - acme-engineer/SKILL.md (original practices) - acquired-engineer/SKILL.md (acquired practices) - routing.md (unified routing) - -acme-product (original product repo) - .squad/ - upstream.json (points to unified-practices) - [business logic] - -acquired-product (acquired product repo) - .squad/ - upstream.json (points to unified-practices) - [business logic] -``` - -**Setup in acquired-product:** - -```bash -squad upstream add https://github.com/acme/acme-unified-practices.git --name unified -``` - -**What happens:** -1. Both products inherit the merged practices -2. Agents understand both organizations' traditions (skills for both) -3. Decisions reflect the merged framework -4. Teams can work independently while being culturally aligned - -**Benefit:** Smooth integration without painful rewrites; shared culture; gradual convergence. - -### Scenario 6: Enterprise Application Modernization - -**Setting:** You're migrating a monolith to microservices. You want to maintain architectural consistency across new services while honoring legacy patterns. - -**Structure:** -``` -modernization-playbook (central guidance repo) - .squad/ - decisions.md (architecture decisions, API patterns) - skills/ - microservice-engineer/SKILL.md (cloud-native practices) - legacy-translator/SKILL.md (backward compatibility) - wisdom.md (migration philosophy) - routing.md (inter-service routing) - -legacy-monolith (old codebase) - .squad/ - upstream.json (points to playbook) - [monolith code] - -billing-service (new microservice) - .squad/ - upstream.json (points to playbook) - [business logic] - -inventory-service (new microservice) - .squad/ - upstream.json (points to playbook) - [business logic] - -shipping-service (new microservice) - .squad/ - upstream.json (points to playbook) - [business logic] -``` - -**Setup in billing-service:** - -```bash -squad upstream add https://github.com/acme/modernization-playbook.git \ - --name playbook -``` - -**What happens:** -1. All new services inherit architectural guidance -2. The legacy monolith inherits it too (preparing for extraction) -3. Playbook defines how services communicate, handle transactions, manage state -4. When a pattern is learned, it goes into the playbook once; all services benefit - -**Benefit:** Architectural coherence; faster service extraction; knowledge base grows with the migration. - -## Troubleshooting - -### Git Clone or Sync Fails - -**Problem:** `git clone` times out or fails with authentication errors. - -**Solutions:** -- Ensure the URL is correct: `https://github.com/owner/repo.git` -- For private repos, use SSH (`git@github.com:owner/repo.git`) and ensure your SSH key is in ssh-agent -- Or use a GitHub PAT with `https://[PAT]@github.com/owner/repo.git` (less secure; prefer SSH) -- Check network: `git clone --depth 1 --branch main ` from the command line first -- If `squad upstream sync` fails, cached clone is stale; run again later - -### Local Upstream Not Found - -**Problem:** `squad upstream add ../shared/.squad` fails with "Cannot determine source type". - -**Solutions:** -- Ensure the path exists: `ls -la ../shared/.squad` -- Ensure it contains a `.squad/` directory (not a `.squad` file) -- Use absolute path if relative paths are ambiguous: `squad upstream add /full/path/to/shared/.squad` -- Verify the other repo is actually a Squad repo (has `.squad/` directory) - -### Export File Invalid - -**Problem:** `squad upstream add ./export.json` fails or doesn't load skills. - -**Solutions:** -- Verify the file is valid JSON: `jq . ./export.json` -- Ensure it was created by `squad export-config` (has the right schema) -- Check that skills array is present: `jq .skills ./export.json` -- If manually created, the structure should be: - ```json - { - "version": "1.0", - "skills": ["", "", ...], - "casting": { "policy": { ... } } - } - ``` - -### Agents Don't See Inherited Context - -**Problem:** Spawned agents don't have access to upstream skills/decisions. - -**Solutions:** -- Verify upstreams are configured: `squad upstream list` -- Verify sources are reachable: `squad upstream sync` (should not warn) -- Check the session display when you start the session (should show `📡 Inherited context:`) -- For git upstreams, ensure they've been cloned: check `.squad/_upstream_repos/{name}` -- For local upstreams, ensure the path still exists -- Restart your session (upstream resolution happens at session start) - -### Cached Clone Gets Out of Date - -**Problem:** You know the upstream repo changed, but agents still see old content. - -**Solution:** -```bash -squad upstream sync -``` - -For all upstreams: -```bash -squad upstream sync -``` - -This updates git clones and validates local/export paths. Then start a new session. - -### Order Matters - -**Problem:** Upstream A and Upstream B define conflicting decisions or skills. - -**Note:** Later entries in `upstream.json` override earlier ones. The resolver reads in order and the last definition wins. - -**Solution:** -Order matters. Check `squad upstream list` to see the order, and use `remove` + `add` to reorder if needed. - ---- - -## Next Steps - -- **Read more:** See `docs/guide/casting.md` for how inherited casting policy shapes agent behavior -- **Set up**: Run `squad upstream add ` to add your first upstream -- **Share:** Export your Squad config with `squad export-config` for others to inherit -- **Iterate:** Update your upstream and run `squad upstream sync` to pull changes across all consuming projects diff --git a/docs/get-started/installation.md b/docs/get-started/installation.md deleted file mode 100644 index e1c4fafaa..000000000 --- a/docs/get-started/installation.md +++ /dev/null @@ -1,166 +0,0 @@ -# Installation - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -Three ways to get Squad running. Pick the one that fits. - ---- - -## Try this: - -```bash -npm install -g @bradygaster/squad-cli -squad -``` - -That's it. You're in. - ---- - -## 1. CLI (Recommended) - -The CLI is the fastest way to use Squad from any terminal. - -### Global install - -```bash -npm install -g @bradygaster/squad-cli -``` - -Now use it anywhere: - -```bash -squad init -squad status -squad watch -``` - -### One-off with npx - -No install needed — run the latest version directly: - -```bash -npx @bradygaster/squad-cli init -npx @bradygaster/squad-cli status -``` - -### Verify - -```bash -squad --version -``` - -### Update - -```bash -npm install -g @bradygaster/squad-cli@latest -``` - ---- - -## 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. - -> **Tip:** Initialize your team with the CLI (`squad`), then open the project in VS Code to keep working with the same squad. - ---- - -## 3. SDK - -Building your own tooling on top of Squad? Install the SDK as a project dependency: - -```bash -npm install @bradygaster/squad-sdk -``` - -Then import what you need: - -```typescript -import { defineConfig, loadConfig, resolveSquad } from '@bradygaster/squad-sdk'; -``` - -The SDK gives you typed configuration, routing, model selection, and the full agent lifecycle API. See the [SDK Reference](../reference/sdk.md) for details. - ---- - -### Personal squad (cross-project) - -Want the same agents across all your projects? - -```bash -squad init --global -``` - -This creates `~/.squad/` — a personal team root that any project can inherit from. See [Upstream Inheritance](../features/upstream-inheritance.md) for details. - ---- - -## First-Time Setup - -After installing, initialize Squad in your project: - -```bash -cd your-project -squad init -``` - -This creates: - -``` -.github/agents/squad.agent.md — coordinator agent -.squad/ — team state directory -``` - -### Configuration (optional) - -For typed configuration, create a `squad.config.ts` at your project root: - -```typescript -import { defineConfig } from '@bradygaster/squad-sdk'; - -export default defineConfig({ - team: { - name: 'my-squad', - root: '.squad', - description: 'My project team', - }, -}); -``` - -`defineConfig()` gives you full autocomplete and validation. But you don't need it to get started — Squad works out of the box with sensible defaults. - ---- - -## Troubleshooting - -### `squad: command not found` - -Your npm global bin isn't in your PATH. Fix: - -```bash -# Check if installed -npm list -g @bradygaster/squad-cli - -# If installed but not found, check PATH: -echo $PATH | grep npm # macOS/Linux -echo %PATH% | findstr npm # Windows -``` - -### `Cannot find .squad/ directory` - -Run `squad init` in your project root, or `squad init --global` for a personal squad. - -### Version mismatch between CLI and SDK - -Update both: - -```bash -npm install -g @bradygaster/squad-cli@latest -npm install @bradygaster/squad-sdk@latest -``` - ---- - -## Ready? → [Your First Session](first-session.md) 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..c0e858c85 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,25 @@ +{ + "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", + "test": "node --test tests/build-output.test.mjs && npx playwright test", + "test:build": "node --test tests/build-output.test.mjs", + "test:e2e": "npx playwright test" + }, + "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/pagefind.yml b/docs/pagefind.yml new file mode 100644 index 000000000..282352e74 --- /dev/null +++ b/docs/pagefind.yml @@ -0,0 +1,12 @@ +# Pagefind configuration for Squad docs +# See: https://pagefind.app/docs/config-options/ + +# Exclude navigation, footers, and code blocks from indexing +exclude_selectors: + - "nav" + - "footer" + - "aside" + - "pre" + - ".astro-code" + + diff --git a/docs/playwright.config.mjs b/docs/playwright.config.mjs new file mode 100644 index 000000000..2c69a1ac9 --- /dev/null +++ b/docs/playwright.config.mjs @@ -0,0 +1,13 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + testMatch: '**/*.spec.mjs', + timeout: 30_000, + retries: 0, + use: { + baseURL: 'http://localhost:4321/squad/', + browserName: 'chromium', + headless: true, + }, +}); diff --git a/docs/sample-prompts.md b/docs/sample-prompts.md deleted file mode 100644 index 328152efe..000000000 --- a/docs/sample-prompts.md +++ /dev/null @@ -1,925 +0,0 @@ -# Sample Prompts - -Ready-to-use prompts that show what Squad can do. Each one describes a project, the kind of team it needs, and what makes it interesting as a Squad demo. - -Copy any prompt below, open Copilot, select **Squad**, and paste it in. - ---- - -## Quick Builds - -These are small enough that a team can ship them in a single session. Good for seeing parallel fan-out, fast iteration, and agents that don't step on each other. - ---- - -### 1. CLI Pomodoro Timer - -``` -I'm building a cross-platform CLI pomodoro timer in Python. It should support: -- Configurable work/break intervals with sensible defaults (25/5/15) -- A persistent stats tracker that logs completed sessions to a local JSON file -- Desktop notifications on macOS, Windows, and Linux -- A "focus mode" that blocks a configurable list of domains by writing to /etc/hosts (with undo on break) -- A --report flag that prints weekly stats as a table - -Set up the team. I want this done fast — everyone works at once. -``` - -**What it demonstrates:** Parallel fan-out on a small, well-scoped project. Backend handles the timer and host-blocking logic, a systems agent handles cross-platform notifications, the tester writes test cases from the spec while implementation is in flight. - ---- - -### 2. Markdown Static Site Generator - -``` -I want a zero-dependency static site generator in Node.js. It takes a folder of markdown files, converts them to HTML using a single built-in template, generates an index page with links to all pages, and outputs everything to a dist/ folder. It should support front matter (title, date, tags), generate tag index pages, and include an RSS feed. No frameworks, no bundlers — just fs, path, and a markdown parser we write ourselves. - -Set up the team and start building. -``` - -**What it demonstrates:** Tight collaboration between agents who own different parts of the pipeline (parser, template engine, RSS generator, file I/O). The tester can write test cases from the spec immediately while the others build. Decisions about front matter format propagate via decisions.md. - ---- - -### 3. Retro Snake Game - -``` -Build a browser-based Snake game using vanilla HTML, CSS, and JavaScript. No frameworks. Requirements: -- Canvas-based rendering at 60fps -- Arrow key and WASD controls -- Score tracking with localStorage high scores -- Progressive speed increase every 5 points -- A retro CRT-style visual effect using CSS filters -- Mobile support via touch swipe controls -- Sound effects using the Web Audio API - -Start building immediately — I want to play this in 20 minutes. -``` - -**What it demonstrates:** A game where frontend, audio, and input handling can all be built in parallel. The tester writes Playwright tests for keyboard input, scoring, and game-over conditions while the game is being built. Fast iteration — agents can see each other's output and adjust. - ---- - -### 4. Turn-by-Turn Text Adventure Engine - -``` -Build a text-based adventure game engine in TypeScript. The engine should: -- Load worlds from JSON files that define rooms, items, NPCs, and transitions -- Support a command parser that handles: go [direction], look, take [item], use [item] on [target], talk to [npc], inventory -- Include a sample adventure with at least 10 rooms, 5 items, 3 NPCs, and 2 puzzles -- Support save/load game state to JSON -- Run in the terminal via Node.js with colored output (chalk) -- Include a "narrator voice" system where room descriptions vary based on items in inventory or previous actions - -Build the engine and the sample adventure at the same time. The content writer and the engine builder should work in parallel. -``` - -**What it demonstrates:** A natural split between engine (parser, state machine, I/O) and content (world design, narrative, puzzles). These two streams can run fully in parallel. The tester writes test cases for command parsing and state transitions from the spec alone. Decisions about data format are shared and respected across streams. - ---- - -### 5. Arcane Duel — A Card Battle Game - -``` -Build a strategic card duel game inspired by Magic: The Gathering, playable in the browser. Two players take turns drawing from a shared deck and playing cards onto a battlefield. Requirements: -- 30+ unique cards across 4 categories: Attack, Defense, Spell, Trap -- Each card has: name, mana cost, power, toughness (if creature), effect text -- Turn phases: Draw → Main (play cards, activate abilities) → Combat (declare attackers/blockers, resolve damage) → End -- Mana system: 1 mana gained per turn, max 10. Some cards generate bonus mana. -- Stack-based spell resolution: spells and traps can be played in response to other spells -- Health points: each player starts at 20 HP, wins when opponent reaches 0 -- AI opponent with basic strategy (prioritize removal, protect low HP, bluff traps) -- Visual battlefield using HTML/CSS grid layout showing each player's field, hand, graveyard -- Card hover preview with full art and effect text - -I want one agent designing the card set and balance, another building the game engine and rules, another building the UI, and someone testing the combat math. Go. -``` - -**What it demonstrates:** Deep parallelism with interdependent design. The card designer and engine builder must share data format decisions early (via decisions.md). The UI agent can scaffold the battlefield while cards are still being designed. The tester validates combat resolution math from the rules spec. This is a project where the Scribe's decision propagation is critical — when the card designer decides on mana curve, the engine and AI both need to know. - ---- - -### Squad Blog Engine (Meta Demo) - -``` -Build a static blog engine that renders markdown blog posts into beautiful HTML pages. -No frameworks — just HTML, CSS, and vanilla JavaScript. - -Input: markdown files from a docs/blog/ directory. Each file has YAML frontmatter -(title, date, author, wave, tags, status, hero). - -Output: -- An index page listing all posts, sorted by date, with title, hero text, author, and tags -- Individual post pages with clean typography, syntax-highlighted code blocks, and responsive tables -- A tag index page that groups posts by tag -- Wave navigation: "← Previous Wave | Next Wave →" links on each post -- Dark mode toggle (CSS custom properties, saved to localStorage) -- RSS feed (feed.xml) - -Design direction: -- Clean, modern, developer-focused. Think GitHub's blog meets a personal dev blog. -- Monospace headings, proportional body text -- Code blocks with a dark theme and copy-to-clipboard button -- Mobile responsive — single column on small screens -- Fast. No JavaScript required for reading — JS only for dark mode toggle and copy button. -- Hero section on the index page with the blog title and a one-liner about the project. - -The markdown parser should handle: headings, paragraphs, lists, code blocks (fenced), -inline code, bold, italic, links, images, blockquotes, horizontal rules, and tables. - -Build the parser, the template engine, the RSS generator, and the static file output. -Put the output in a dist/ folder. Include a build script that can be run with -`node build.js` to regenerate the site. - -Set up the team and build it. I want to see this running in one session. -``` - -**What it demonstrates:** The ultimate meta-demo — Squad builds the tool that publishes Squad's own progress story. Input is markdown files Squad already writes (wave completion posts in `docs/blog/`). Parser, templating, RSS, and responsive CSS can all be built in parallel. The finished product is visual (screenshots well), functional (actually renders real content), and narratively perfect: "Squad built this to tell you about itself." - ---- - -## Mid-Size Projects - -These need real coordination. Agents make architectural decisions, share them, and build on each other's work across multiple rounds. - ---- - -### 6. Cloud-Native E-Commerce Store - -``` -Build an event-driven e-commerce store with these services: -- Product Catalog API (Node.js/Express, PostgreSQL) — CRUD for products with categories and search -- Order Service (Node.js) — accepts orders asynchronously via a message queue, validates inventory, processes payment stubs, emits order-status events -- Notification Service — listens for order events, sends email confirmations (stub/log) -- API Gateway — routes requests, handles auth (JWT), rate limiting -- Message queue: use RabbitMQ (or an in-memory stub for local dev) -- Frontend: React SPA with product grid, cart, checkout flow - -Each service should be independently deployable with its own Dockerfile. Include a docker-compose.yml that brings up the entire system. The order flow must be fully asynchronous — the checkout endpoint returns 202 Accepted immediately, and order status is polled or pushed via WebSocket. - -Set up a team. I want each service owned by a different agent. Let them coordinate on API contracts and event schemas early, then build in parallel. -``` - -**What it demonstrates:** True microservice parallelism. Each service agent works independently after agreeing on contracts (shared via decisions.md). The tester writes integration tests for the order flow end-to-end. Agents must share event schema decisions early — Scribe propagation matters. The API gateway agent can scaffold while downstream services are being built. - ---- - -### 7. Playwright-Tested Dashboard App - -``` -Build a project management dashboard using React + TypeScript with a Node.js/Express backend. Features: -- Kanban board with drag-and-drop (columns: Backlog, In Progress, Review, Done) -- Task creation with title, description, assignee, priority, due date -- Filtering by assignee, priority, and status -- Real-time updates via WebSocket (when one user moves a card, others see it) -- User auth with login/signup (JWT, bcrypt) -- SQLite database with Drizzle ORM - -Testing requirements (critical — this is the demo): -- Full Playwright test suite covering: - - Login flow (valid credentials, invalid credentials, session persistence) - - Task CRUD (create, edit, delete, verify persistence after refresh) - - Drag-and-drop (move task between columns, verify state update) - - Filtering (apply filters, verify correct tasks shown, clear filters) - - Real-time sync (open two browser contexts, move card in one, verify update in other) -- Generate Gherkin feature files (.feature) for every user story FIRST, then implement Playwright step definitions -- Tests must be runnable with `npx playwright test` and produce an HTML report - -Set up the team. I want the Gherkin specs and Playwright tests written from requirements BEFORE the implementation starts, then updated as the real UI takes shape. -``` - -**What it demonstrates:** Test-first parallel development. The tester writes Gherkin feature files and Playwright test skeletons immediately from the requirements — no waiting for implementation. Frontend and backend build in parallel. Once the UI exists, the tester updates tests to match actual selectors. This shows Squad's anticipatory work pattern at its best: tests and implementation converge without blocking each other. - ---- - -### 8. GitHub Copilot Extension - -``` -Build a GitHub Copilot Chat extension using the Copilot Extensions SDK (https://github.com/copilot-extensions). The extension should: -- Act as a "Code Reviewer" agent that users can invoke via @code-reviewer in Copilot Chat -- Accept a GitHub repo URL or PR number as input -- Fetch the diff (via GitHub API) and analyze it for: - - Security issues (SQL injection, XSS, hardcoded secrets, insecure deserialization) - - Performance concerns (N+1 queries, unbounded loops, missing pagination) - - Style violations (configurable rules loaded from a .code-reviewer.yml in the target repo) -- Return structured feedback as a Copilot Chat response with file-level annotations -- Include a Blackbeard-style SSE streaming response handler per the SDK patterns -- Deploy as a Vercel serverless function -- Include a manifest file for registering as a GitHub App - -Read the Copilot Extensions SDK docs and examples carefully. One agent should own the SDK integration and streaming protocol, another should own the analysis engine, another should own the GitHub API integration. Set up the team. -``` - -**What it demonstrates:** Agents that need to read external documentation and build to an SDK's patterns. The SDK integration agent and the analysis engine agent work in parallel — one handles the protocol, the other handles the logic. They agree on the interface contract via decisions.md. Shows Squad working with real-world APIs and deployment targets. - ---- - -### 9. .NET Aspire Cloud-Native App - -``` -Build a cloud-native application using .NET Aspire. Read https://learn.microsoft.com/en-us/dotnet/aspire/ for the Aspire programming model. - -The app is a real-time weather dashboard: -- AppHost project orchestrating all services -- Frontend: Blazor Server dashboard showing current conditions and 5-day forecast for saved cities -- Weather API service: wraps OpenWeatherMap API with caching (Redis via Aspire integration) -- User Preferences service: stores saved cities per user (PostgreSQL via Aspire integration) -- Background Worker: refreshes cached weather data every 15 minutes for all saved cities (uses Aspire Worker template) -- Service-to-service communication via Aspire service discovery (no hardcoded URLs) -- Health checks and OpenTelemetry tracing via Aspire defaults - -I want the team organized by Aspire integration: -- One agent owns the AppHost and service discovery wiring -- One agent owns the Redis caching integration -- One agent owns the PostgreSQL data layer -- One agent owns the Blazor frontend -- One agent owns the background worker -- The tester validates that services discover each other and data flows end-to-end - -Set up the team. Each agent should understand their specific Aspire integration deeply. -``` - -**What it demonstrates:** Agents specialized by infrastructure integration rather than traditional roles. Each agent is an expert in one Aspire component. The AppHost agent coordinates wiring while service agents build independently. Decisions about service names and connection strings propagate through decisions.md. Shows Squad handling a .NET-specific ecosystem with genuine infrastructure concerns. - ---- - -## Large Projects - -These push coordination, memory, and team size. Multiple rounds of work, cross-cutting decisions, and agents that need to remember what happened earlier. - ---- - -### 10. Legacy .NET-to-Azure Migration - -``` -I have a legacy .NET Framework application that needs to be migrated to Azure. Clone these two repos to start: - -1. https://github.com/bradygaster/ProductCatalogApp — ASP.NET MVC (.NET Framework) web app with: - - Product catalog with shopping cart functionality - - WCF service (SOAP) for product data access - - In-memory product repository - - Order submission to MSMQ (Message Queue) - - jQuery-based frontend - -2. https://github.com/bradygaster/IncomingOrderProcessor — Windows Service that: - - Monitors MSMQ for incoming orders - - Processes and logs orders from the queue - - Runs continuously as a background service - -The migration target: -- ProductCatalogApp → ASP.NET Core MVC (.NET 10) or Blazor on Azure App Service - - Replace WCF SOAP service with ASP.NET Core Web API (REST) - - Keep in-memory repository initially, but structure for Azure SQL migration - - Replace MSMQ with Azure Service Bus queues - - Modernize frontend (keep MVC or migrate to Blazor) -- IncomingOrderProcessor → Azure Functions (.NET 8) with Service Bus trigger - - Convert Windows Service to serverless function - - Trigger on Service Bus queue messages - - Maintain same order processing logic -- Shared models → .NET 10 class library used by both services -- Infrastructure: Bicep templates for App Service, Function App, Service Bus namespace and queue -- CI/CD: GitHub Actions workflows for both services -- Local dev: docker-compose or Aspire for running everything locally - -Migration rules: -- Preserve all business logic — orders must flow identically -- WCF SOAP contracts become REST APIs with the same data structures -- MSMQ queue becomes Azure Service Bus queue with compatible message format -- The Windows Service becomes a Service Bus-triggered Azure Function -- All services must work locally before Azure deployment - -I need a migration team: one agent for the web app migration, one for the WCF-to-API conversion, one for the Windows Service-to-Functions migration, one for shared models, one for Azure infrastructure (Bicep), one for CI/CD, and a tester who validates that orders flow end-to-end correctly. Set up the team and start with the migration plan. -``` - -**What it demonstrates:** The most realistic Squad scenario — migrating actual legacy .NET Framework code to modern Azure. The team must understand existing WCF patterns, MSMQ messaging, Windows Services, and translate them to Azure-native equivalents (REST APIs, Service Bus, Functions). Shows true enterprise migration challenges: agents analyze unfamiliar code, preserve business logic while modernizing infrastructure, coordinate on message formats and shared models, and validate behavioral equivalence across the migration. - ---- - -### 11. Multiplayer Space Trading Game - -``` -Build a multiplayer space trading game playable in the browser. Think Elite Dangerous meets a browser game. - -Game systems: -- Galaxy map: procedurally generated star systems (50+) with stations, connected by trade routes -- Economy: each station buys/sells commodities (fuel, ore, food, tech, luxuries) at dynamic prices driven by supply/demand -- Ships: 3 tiers (shuttle, freighter, cruiser) with cargo capacity, fuel range, and hull strength -- Trading: buy low, sell high. Prices shift based on player activity and random events -- Combat: simple turn-based encounters with pirates or other players at jump points -- Multiplayer: WebSocket-based real-time. Players see each other on the galaxy map. Chat. PvP opt-in. -- Persistence: player state (credits, cargo, location, ship) saved to PostgreSQL -- Frontend: Canvas-based galaxy map, HTML/CSS panels for station UI, trading, inventory - -Tech stack: Node.js backend, PostgreSQL, WebSocket (ws), vanilla HTML/CSS/Canvas frontend. - -I want one agent on the economy/trading engine, one on the galaxy generator and map rendering, one on combat mechanics, one on multiplayer/networking, one on the frontend UI panels, and the tester. The economy designer and galaxy generator can work simultaneously — they just need to agree on the star system data format early. Go. -``` - -**What it demonstrates:** A complex game with 6+ agents, each owning a distinct game system that must interoperate. Data format decisions (star system schema, ship stats, commodity definitions) are shared early and respected across all agents. The economy and galaxy agents work in parallel from turn 1. Combat and multiplayer can scaffold independently. The tester writes test cases for trade math, combat resolution, and economy simulation before implementation is final. - ---- - -### 12. AI Recipe App with Image Recognition - -``` -Build a recipe app where users can photograph ingredients and get recipe suggestions. Tech stack: React Native (Expo) frontend, Python FastAPI backend, SQLite. - -Features: -- Camera capture: user photographs ingredients on a counter -- Image analysis: send photo to a vision model (use OpenAI's GPT-4 Vision API) to identify ingredients -- Recipe matching: match identified ingredients against a recipe database (seed with 50+ recipes) -- Recipe display: ingredients list (highlighting what you have vs. what you need), step-by-step instructions, estimated time -- Favorites: save recipes, rate them, add notes -- Shopping list: auto-generate a list of missing ingredients -- Dietary filters: vegetarian, vegan, gluten-free, dairy-free - -I want one agent on the React Native frontend, one on the FastAPI backend and database, one on the vision/AI integration, one curating the recipe database and seed data, and the tester writing API tests and mocking the vision responses. Set up the team. -``` - -**What it demonstrates:** Cross-platform mobile + backend + AI integration. The recipe curator and the AI integration agent can work simultaneously — one builds the database, the other figures out the vision API interface. They agree on the ingredient taxonomy via decisions.md. The tester mocks vision API responses to write deterministic tests before the real integration exists. Shows Squad handling AI/ML service integrations. - ---- - -### 13. DevOps Pipeline Builder - -``` -Build a self-service DevOps platform where teams can define their CI/CD pipelines through a web UI. Tech stack: React frontend, Go backend, PostgreSQL, Docker. - -Features: -- Pipeline designer: drag-and-drop UI for composing pipeline stages (build, test, deploy, notify) -- Stage templates: pre-built stages for common tasks (npm build, Docker build, Helm deploy, Slack notify) -- Pipeline execution: stages run as Docker containers orchestrated by the Go backend -- Live logs: stream build output to the browser via SSE -- Pipeline-as-code: export/import pipelines as YAML (compatible with GitHub Actions syntax) -- Secrets management: encrypted storage for API keys, registry credentials -- Execution history: searchable log of all pipeline runs with status, duration, artifacts - -I need a frontend agent for the drag-and-drop pipeline designer, a backend agent for the execution engine, a Docker/infrastructure agent for container orchestration, a security agent for secrets management, and a tester. Set up the team. -``` - -**What it demonstrates:** Agents with very different expertise domains (UI drag-and-drop, container orchestration, cryptography) working on a single product. The execution engine and pipeline designer can be built in parallel once they agree on the pipeline data model. The security agent works independently on secrets encryption. Shows Squad handling infrastructure-heavy projects. - ---- - -### 14. Roguelike Dungeon Crawler - -``` -Build a browser-based roguelike dungeon crawler. Procedurally generated dungeons, permadeath, turn-based combat. - -Requirements: -- Dungeon generation: procedural rooms + corridors using BSP or cellular automata, 10 floors with increasing difficulty -- Character: warrior/mage/rogue classes with unique abilities (3 each), health/mana/stamina stats -- Combat: turn-based, grid-positioned. Melee, ranged, and AoE attacks. Enemy AI that flanks, retreats when low HP, and uses abilities -- Items: weapons, armor, potions, scrolls. Random loot tables per floor. Item identification system (unidentified scrolls/potions until used) -- Fog of war: tile-based visibility using raycasting from player position -- Rendering: HTML5 Canvas with tilemap. 16x16 or 32x32 pixel art style (use simple colored squares if no art assets) -- Permadeath: when you die, it's over. High score table with character name, class, floor reached, cause of death -- Save system: save-on-exit only (no save scumming). LocalStorage. - -I want one agent on dungeon generation, one on combat + enemy AI, one on items + loot tables, one on rendering + fog of war, and the tester. These can all build simultaneously as long as they agree on the tile/entity data model. Start building. -``` - -**What it demonstrates:** Game systems that are independently buildable but share a common data model. Dungeon generation, combat, items, and rendering are four parallel streams that converge on a shared entity/tile format. The early decision on data model (via decisions.md) enables full parallelism. The tester validates combat math, loot distribution, and fog of war calculations from specs. - ---- - -### 15. Real-Time Collaborative Whiteboard - -``` -Build a real-time collaborative whiteboard app using React Flow for the node/shape editor. Think Miro or Excalidraw but simpler. Tech stack: React + TypeScript + React Flow frontend, Node.js backend, WebSocket. - -Features: -- Built on React Flow (https://reactflow.dev/) for drag-and-drop node-based editing -- Shape library: rectangles, circles, text nodes, sticky notes, arrows/edges connecting shapes -- Drag-and-drop: users can drag shapes from a palette onto the canvas, drag to reposition, drag handles to resize -- Color picker, stroke width, fill color, background color per shape -- Connect shapes with arrows (React Flow edges) — drag from one shape to another -- Select multiple shapes (bounding box selection), move/delete/style as a group -- Real-time sync: multiple users see each other's cursors and edits via WebSocket -- Rooms: shareable URL creates a room, anyone with the link can join -- Undo/redo per user (each user has their own undo stack) -- Export to PNG and SVG (React Flow has built-in export utilities) -- Persistence: save canvas state (nodes, edges, viewport) to PostgreSQL, auto-save every 30 seconds - -I want a frontend agent owning the React Flow integration and drag-and-drop interactions, a networking agent owning the WebSocket sync and conflict resolution (CRDT or OT for canvas state), a backend agent owning rooms and persistence, and a tester writing Playwright tests for multi-user drag-and-drop scenarios. Set up the team and build it. -``` - -**What it demonstrates:** A project where the networking/sync agent and the frontend agent must closely coordinate on the React Flow data model (nodes, edges, viewport state). The frontend agent leverages React Flow's built-in drag-and-drop and handles, while the networking agent syncs changes across users. The backend agent can work independently on rooms and persistence. The tester writes multi-context Playwright tests (two browsers in one test) to validate real-time drag-and-drop sync — a direct showcase of Playwright's multi-page testing and React Flow's powerful node-based editor capabilities. - ---- - -### 16. Multiplayer Dice Roller — Bar Games PWA - -``` -Build a mobile-first Progressive Web App for rolling dice with friends at a bar. The vibe: tapping your phone on a virtual green velvet table, realistic 3D dice tumbling across the screen. Tech stack: React + TypeScript, Three.js (or React Three Fiber), Node.js + WebSocket backend, PostgreSQL. - -Features: -- Mobile-first responsive design: works perfectly on phones, tablets, and desktop -- PWA: installable on home screen, works offline (cached dice rolls when disconnected, sync when back online) -- Double-tap gesture: tap the screen twice anywhere to roll the dice — they bounce and tumble realistically across a green velvet table -- 3D dice physics: use Three.js or React Three Fiber for realistic dice with physics simulation (gravity, bounce, spin, settle) -- Customizable dice: choose number of dice (1-10), die type (d6, d10, d12, d20), color schemes -- Real-time multiplayer: - - Create a room with a shareable 6-digit code or QR code - - Friends join the same room via code or QR scan - - Everyone sees everyone's rolls in real-time with player names - - Room chat for banter and trash talk -- Game modes with score tracking: - - Freeroll: just roll, no rules, all rolls logged - - Yahtzee: automated scoring, tracks categories, end-of-game leaderboard - - Liar's Dice: player declarations, challenge system, elimination rounds - - Custom: define your own scoring rules (high roll wins, sum target, etc.) -- Score history: view roll history for the session, replay animations, export session log as JSON -- Sound effects: dice clatter, table bounce (mute toggle) -- Haptic feedback on mobile: vibrate on roll, on settle -- Night mode: dark UI with brighter dice for late-night bar sessions - -I want one agent on the Three.js 3D dice rendering and physics, one agent on the mobile PWA setup and touch gesture handling, one agent on the real-time multiplayer backend (rooms, WebSocket, score sync), one agent on game logic (different game modes, scoring rules, turn management), and a tester writing mobile Playwright tests for touch gestures and multiplayer roll sync. Set up the team and build it. -``` - -**What it demonstrates:** A mobile-first project where agents specialize by concern: 3D graphics, touch UX, real-time networking, and game logic. The 3D agent and the gesture agent must coordinate on the tap-to-roll trigger and animation states. The game logic and networking agents share data models for scores and turns. The PWA requirements (offline support, install prompt) and mobile testing (touch events, multi-device Playwright tests) showcase Squad handling production mobile app concerns. This is also a fun, visual demo — you can actually play dice games with the finished product. - ---- - -## Feature Showcases - -These prompts are designed to exercise Squad's advanced features — export/import, skills, ceremonies, PRD mode, GitHub Issues, human team members, and more. Each one is a real project where the feature shows up naturally. - ---- - -### 17. Cross-Platform Habit Tracker — Portable Squad - -``` -I built a CLI habit tracker with a Squad last month in another repo. I exported the squad with `npx github:bradygaster/squad export` and I have the squad-export.json file ready. - -Import it into this repo with `npx github:bradygaster/squad import squad-export.json`. - -Now let's build a cross-platform habit tracker with a React Native (Expo) frontend and a Node.js backend: -- Daily habit check-ins with streaks, miss tracking, and weekly summaries -- Habit categories (health, learning, productivity) with custom icons -- Push notification reminders at user-configured times -- SQLite local-first storage with optional cloud sync (Supabase) -- Charts: streak heatmap (GitHub-style), weekly completion rate, category breakdown -- Widget support for iOS and Android home screens - -The team should already know my preferences from the last project. Start building. -``` - -**What it demonstrates:** Export/import in action. The squad arrives with earned preferences and skills from a previous project — coding style, testing patterns, communication style. The user doesn't re-explain anything. The team picks up where it left off, in a brand new repo. This is the "holy crap, it remembers me" moment. - ---- - -### 18. Open Source Contribution Dashboard — GitHub Issues + Skills - -``` -Pull issues from bradygaster/squad. Show me the open issues and let me pick which ones to work on. - -While we're at it, the team should build skills as they go — if someone figures out a pattern for testing CLI installers or working with the Copilot Extensions SDK, write it down as a skill so the team gets better over time. -``` - -**What it demonstrates:** GitHub Issues Mode — connecting to a real repo, listing the backlog, and letting the user pick issues for agents to claim. Each issue flows through the full lifecycle: branch, implement, PR. The skills instruction shows how agents earn reusable SKILL.md files as they work, building team competence that persists across sessions. - ---- - -### 19. Event-Driven Inventory System — PRD + Ceremonies - -``` -Here's the PRD at docs/inventory-prd.md — it describes an event-driven inventory management system for a small warehouse operation. - -Before the team starts building, run a design review. I want the Lead to decompose the PRD into work items first, then the team should discuss architecture choices (event sourcing vs. CRUD, message broker selection, data model) before anyone writes code. - -Tech constraints from the PRD: -- Node.js services, PostgreSQL, Redis for event streaming -- REST API for external integrations, WebSocket for real-time dashboard -- Barcode scanner input via serial port (node-serialport) -- Audit log for every inventory mutation -``` - -**What it demonstrates:** PRD Mode and Ceremonies working together. The PRD gets ingested and decomposed into work items by the Lead. A design review ceremony runs before implementation — agents align on architecture, surface trade-offs, and make shared decisions. The ceremony creates alignment that prevents rework. This is how a real team operates: read the spec, discuss, then build. - ---- - -### 20. Developer Portfolio Site — Human Team Member + Tiered Responses - -``` -I'm building a developer portfolio site. Add my teammate Sarah as Designer — she'll handle visual direction, color palette, and layout decisions. The rest of the team builds it: - -- Next.js static site with MDX blog posts -- Project showcase with live demo embeds (CodeSandbox/StackBlitz) -- Interactive terminal-style "about me" section (type commands, get responses) -- Dark/light theme with system preference detection -- Lighthouse score targets: 100 performance, 100 accessibility -- Contact form with Resend for email delivery -- RSS feed and open graph meta tags for social sharing - -When work needs Sarah's design input, pause and ask her. Don't guess on visual decisions. -``` - -**What it demonstrates:** Human team members and tiered response modes. Adding Sarah as Designer puts a real person on the roster — when work routes to her domain (color choices, layout, typography), Squad pauses and asks for her input instead of guessing. Meanwhile, the tiered response system handles the spectrum: quick questions get instant answers (Direct mode), config tweaks get lightweight edits, and the full build fans out across multiple agents (Full mode). The team adapts its effort to the task size automatically. - ---- - -### 21. API Client SDK Generator — Skills + Smart Upgrade - -``` -Before we start, run `npx github:bradygaster/squad` to make sure we're on the latest version. - -Now build an SDK generator that takes an OpenAPI 3.1 spec and produces typed client libraries: -- TypeScript SDK with fetch-based HTTP client, Zod runtime validation, and full JSDoc -- Python SDK with httpx, Pydantic models, and type hints -- Auto-generated test suites for both SDKs (mock server from the spec) -- CLI tool: `sdkgen generate --spec api.yaml --lang typescript --output ./sdk/` -- Watch mode: re-generate when the spec file changes -- Changelog diff: when the spec changes, output a human-readable summary of what changed in the API - -Each language generator is a plugin. The architecture should make adding a Go or Rust generator later trivial. - -As the team works, they should write skills for patterns they discover — OpenAPI parsing edge cases, code generation techniques, test mocking strategies. These should be reusable on future SDK projects. -``` - -**What it demonstrates:** Smart upgrade and skills. Running `npx github:bradygaster/squad` in an existing repo detects version differences and migrates — the team gets new capabilities without losing any state. As agents build the SDK generator, they write SKILL.md files for patterns they discover (OpenAPI parsing quirks, code generation idioms). Those skills persist and inform future work — the next time this squad tackles an API project, it arrives with earned expertise. - ---- - -### 22. Community Recipe Book — GitHub Issues + Human Team + History Summarization - -``` -Pull issues from our-org/community-recipes. These are feature requests from our users for a community recipe sharing platform. - -Add my teammate Alex as Content Lead — they'll review recipe data models and taxonomy decisions. When there's a question about how to categorize cuisines or structure ingredient lists, ask Alex. - -The platform: -- Next.js app with Prisma + PostgreSQL -- User-submitted recipes with rich text editor (Tiptap) -- Ingredient parser that handles natural language ("2 large eggs, beaten" → structured data) -- Dietary tags with smart detection (scan ingredients for common allergens) -- Recipe scaling (adjust servings, recalculate quantities) -- Social features: favorites, collections, comments, user profiles -- Full-text search with filters (cuisine, dietary, cook time, difficulty) - -We've been working on this for a few sessions now. The Scribe should summarize older history entries to keep things compact — we don't need the play-by-play from three sessions ago, just the decisions and learnings. -``` - -**What it demonstrates:** Three features in one natural workflow. GitHub Issues Mode pulls real user requests from the backlog. A human team member (Alex) owns content decisions — the team pauses for their input on taxonomy and data modeling. History summarization keeps the team's memory compact after multiple sessions: the Scribe progressively summarizes older entries, archiving the originals so nothing is lost but the working context stays lean. This is what a mature, multi-session project looks like. - ---- - -### 23. IoT Dashboard — Full Ceremony Lifecycle + PRD + Export - -``` -Here's the PRD at specs/iot-dashboard.md — it describes a real-time IoT sensor dashboard for a small manufacturing floor. - -Run a design review before building. After the first milestone ships, run a retro — I want the team to reflect on what worked and what didn't. - -Requirements from the PRD: -- React dashboard with real-time sensor charts (Recharts + WebSocket) -- Node.js ingestion service accepting MQTT messages from sensors -- TimescaleDB for time-series storage with automatic data retention policies -- Alert rules engine: threshold alerts, rate-of-change alerts, dead sensor detection -- Multi-tenant: each manufacturing client sees only their sensors -- Historical data export to CSV and JSON - -When we're done, export the squad — I want to bring this team's knowledge to our next IoT project. -``` - -**What it demonstrates:** The full ceremony lifecycle plus PRD Mode and export. A design review ceremony runs before the team touches code — agents align on architecture for a complex real-time system. After the first milestone, a retro ceremony captures what worked and what to improve. PRD Mode structures the entire build around a spec document. When the project wraps, `npx github:bradygaster/squad export` captures everything the team learned — MQTT patterns, time-series strategies, alert engine design — as a portable snapshot ready for the next project. - ---- - -## v0.2.0 Feature Prompts - -Quick prompts that exercise specific v0.2.0 features. Use these to try out individual capabilities without building a full project. - ---- - -### Export & Import - -``` -Export this squad so I can use it in another repo. -``` - -``` -npx github:bradygaster/squad export -``` - -``` -Import the squad from my previous project: npx github:bradygaster/squad import squad-export.json -``` - -``` -Export just the team state — I want to send the snapshot to a colleague starting a similar project. -``` - -``` -I imported a squad from another repo. Show me what the team remembers from the previous project. -``` - ---- - -### GitHub Issues - -``` -Connect to our GitHub repo and pull the open issues. Show me the backlog. -``` - -``` -Which issues are highest priority? Let the Lead triage and assign them to the right agents. -``` - -``` -Work issue #42 — the Lead should break it down and assign the right agent. Create a branch, implement, and open a PR. -``` - -``` -Show me all issues the team has completed this session. Summarize what was done for each one. -``` - -``` -Close issue #15 and merge the PR — the tester confirmed it passes. -``` - ---- - -### PRD Mode - -``` -Here's our PRD at docs/product-requirements.md — ingest it and decompose it into work items. -``` - -``` -Show me the work items from the PRD. Which ones are ready to start and which are blocked? -``` - -``` -The PRD has been updated — re-read docs/product-requirements.md and flag any new or changed requirements. -``` - -``` -Map the PRD work items to team members. Who owns what? -``` - ---- - -### Human Team Members - -``` -Add my teammate Jordan as Designer — they'll handle visual direction and UX decisions. -``` - -``` -Remove the human designer from the team — we're past the design phase. -``` - -``` -When work involves database schema decisions, route it to Alex instead of having the AI decide. -``` - -``` -Show me the team roster. Which members are AI and which are human? -``` - -``` -The frontend needs a color palette. Pause and ask Jordan — don't guess on visual decisions. -``` - ---- - -### Skills - -``` -What skills has the team earned so far? Show me the full skill inventory. -``` - -``` -Show me the confidence levels for the frontend agent's skills. Which ones are mature? -``` - -``` -The backend agent figured out a caching pattern that works well. Write it as a skill so the team remembers it. -``` - -``` -Which skills have decayed? Are there any the team should refresh by practicing again? -``` - ---- - -### Ceremonies - -``` -Run a retro — I want the team to reflect on what worked and what didn't this sprint. -``` - -``` -Before we start building, run a design review. The Lead should present the architecture and the team should challenge it. -``` - -``` -Run a standup — each agent reports what they did, what they're doing next, and any blockers. -``` - -``` -Create a custom ceremony called "Demo Day" where each agent presents what they built and the team gives feedback. -``` - -``` -Schedule a retro after every third session automatically. -``` - ---- - -## v0.3.0 Feature Prompts - -Quick prompts that exercise specific v0.3.0 features. Use these to try out individual capabilities. - ---- - -### Ralph — Work Monitor - -``` -Enable Ralph to watch the team's work. Start monitoring background task execution. -``` - -``` -Check Ralph's status — show me what the team is currently working on and task queue depth. -``` - -``` -Ralph, configure idle-watch mode. Alert me if an agent hasn't made progress for more than 10 minutes. -``` - -``` -Scope Ralph's monitoring to just the backend agent. Ignore frontend for now. -``` - -``` -Show me Ralph's activity log for the past hour — what tasks completed, what failed, what's queued? -``` - ---- - -### Per-Agent Model Selection - -``` -Override the model for the backend agent — use Claude Opus for complex database design instead of the default. -``` - -``` -Run this feature with a cheaper model to save costs. Use GPT-4 Mini for the frontend work. -``` - -``` -Bump the Lead's model to Claude Opus for this session. We need better reasoning for architecture decisions. -``` - -``` -The frontend agent just used Haiku for the styling work. Show me what model was used. -``` - -``` -Set up model rotation: use Opus for design reviews, Sonnet for implementation, Haiku for tests. -``` - ---- - -### @copilot Coding Agent - -``` -Add @copilot to the team as the coding specialist. Auto-assign code generation and refactoring to them. -``` - -``` -Configure @copilot to handle all TypeScript work. Route TypeScript issues directly to them. -``` - -``` -Show me @copilot's capabilities. What can they do and what do they need human review on? -``` - -``` -@copilot just finished the component refactor. Review their work before I merge. -``` - -``` -Remove @copilot from the team. We're doing code review manually going forward. -``` - ---- - -### Labels & Triage - -``` -Add priority labels to all open issues. What's critical vs. nice-to-have? -``` - -``` -Show me the triage status for issue #42. Who said what about the verdict? -``` - -``` -Change the verdict on issue #8 from "blocked" to "ready-to-start" — the dependency is resolved. -``` - -``` -Tag issues for the v1.0 release. Show me what's targeted for the next milestone. -``` - -``` -Set priority: mark frontend bugs as P1, documentation updates as P3. -``` - ---- - -### Directives - -``` -Set a coding style preference: prefer functional components over class components in React. -``` - -``` -Add a scope constraint: don't touch authentication logic without explicit approval from the Lead. -``` - -``` -Set a process rule: all pull requests must have a code review before merging. -``` - -``` -Show me the team's current directives. What rules are we following? -``` - -``` -Update the documentation preference: use JSDoc for all public functions with @param and @return tags. -``` - ---- - -### Parallel Execution - -``` -Start these three tasks in parallel: implement the API endpoint, write tests, and update docs. -``` - -``` -Run this work in sync mode — I want real-time output instead of background execution. -``` - -``` -Check the status of my background agents. Which tasks completed and which are still running? -``` - -``` -The frontend and backend agents are working in parallel. Show me their progress separately. -``` - -``` -Cancel the background task for the database migration — we're taking a different approach. -``` - ---- - -### Reviewer Protocol - -``` -Request a code review from Alex before this PR merges. They're our database expert. -``` - -``` -The reviewer rejected my changes. Show me their feedback and what needs to be fixed. -``` - -``` -Reassign the PR review to Jordan — the original reviewer is busy with another task. -``` - -``` -I've addressed the review feedback. Re-request approval from the reviewer. -``` - -``` -Show me all PRs waiting for review. Who's blocking and when did they last respond? -``` - ---- - -### Worktree Awareness - -``` -I'm working in a git worktree. Update the team root path so commands run in the right directory. -``` - -``` -Switch to a different worktree strategy — we're rotating who works on what branch. -``` - -``` -Show me the team root location. Confirm we're pointing at the right working directory. -``` - -``` -The worktree was deleted. Recover the team state and pick a new working directory. -``` - -``` -I need to work on multiple features in parallel using worktrees. Help me set up the team for that workflow. -``` diff --git a/docs/scenarios/release-process.md b/docs/scenarios/release-process.md deleted file mode 100644 index df101f4e1..000000000 --- a/docs/scenarios/release-process.md +++ /dev/null @@ -1,627 +0,0 @@ -# Release Process for Squad Maintainers - -**Try this to ship a new version:** -``` -We're ready to ship v1.2.0 — run the release process: changelog, tags, and publish -``` - -**Try this to promote to production:** -``` -Merge preview to main and cut a production release -``` - -Complete step-by-step guide for Squad maintainers: three-branch model (dev/preview/main), guard workflows, PR merging, and production release procedures. - ---- - -## Table of Contents - -1. [Branch Model Overview](#branch-model-overview) -2. [Preview Build Workflow](#preview-build-workflow) -3. [Pull Request Workflow](#pull-request-workflow) -4. [Merging Back to Dev](#merging-back-to-dev) -5. [Full Release Lifecycle](#full-release-lifecycle) -6. [Branch Protection Rules](#branch-protection-rules) -7. [Testing the Guard Workflow](#testing-the-guard-workflow) -8. [Troubleshooting](#troubleshooting) -9. [Sample Prompts](#sample-prompts) - ---- - -## Branch Model Overview - -Squad uses a **three-branch model** for release safety: - -| Branch | Purpose | Who Commits | Guard Active? | Files Allowed | -|--------|---------|------------|---------------|---------------| -| **dev** | Development — all work happens here | All team members | ❌ No | Everything (`.ai-team/`, team-docs, etc.) | -| **preview** | Staging/testing — validated product only | Release coordinator | ✅ Yes | Distribution files only (`.ai-team/` blocked) | -| **main** | Production — release source for `npx` | Release coordinator | ✅ Yes | Distribution files only (`.ai-team/` blocked) | - -**Key principle:** `.ai-team/` (team state) and internal `team-docs/` (except blog) never leave dev. When code ships, it ships clean. - ---- - -## Preview Build Workflow - -Purpose: Create a staging environment to test the full release before pushing to production. - -### Step 1: Create the Preview Branch - -Start on `dev` and ensure you have the latest commits: - -```bash -git checkout dev -git pull origin dev -``` - -Create a preview branch (or reset if it exists): - -```bash -git checkout -b preview 2>/dev/null || git checkout preview -git reset --hard dev -``` - -### Step 2: Remove Forbidden Files (Guard Enforcement) - -Before pushing to `preview`, remove forbidden paths that the guard workflow will block: - -```bash -# Remove .ai-team/ (keep local copy via .gitignore) -git rm --cached -r .ai-team/ - -# Remove team-docs/ -git rm --cached -r team-docs/ -``` - -If nothing was removed, that's fine: - -```bash -git status -# On branch preview -# nothing to commit, working tree clean -``` - -If there are changes: - -```bash -git commit -m "chore: remove forbidden paths for preview branch" -git push -f origin preview -``` - -### Step 3: Review and Test - -Verify your release PR is ready for merge by checking CI status in GitHub. Ensure all tests pass and code review is complete: - -```bash -# View PR status -gh pr view --web -``` - -Expected output: ✅ All checks pass and PR is approved. - -If checks fail, review the logs and fix any issues. - -### Step 4: Test on Preview - -Push test branches off `preview` and create PRs back to `preview` to validate the release: - -```bash -# Create a feature branch off preview -git checkout -b test/release-validation -echo "# Release validation" > RELEASE_TEST.md -git add RELEASE_TEST.md -git commit -m "test: release validation" -git push -u origin test/release-validation -``` - -Create a PR via `gh`: - -```bash -gh pr create --base preview --title "Release validation test" --body "Validate preview build." -``` - -The guard checks this PR. If it passes, your preview branch is clean. - ---- - -## Pull Request Workflow - -### Creating a PR (Feature Work on Dev) - -When a feature is complete on `dev`, create a PR for review: - -```bash -git checkout -b feature/my-feature -# ... make changes ... -git add . -git commit -m "feat: my new feature" -git push -u origin feature/my-feature -``` - -Create the PR: - -```bash -gh pr create --base dev --title "feat: my new feature" --body "Description of changes" -``` - -### Reviewing a PR - -Reviewers use the GitHub UI or `gh` CLI: - -```bash -# View open PRs -gh pr list --base dev - -# Review a specific PR -gh pr view 123 --web -``` - -Comments, approvals, and change requests flow through GitHub. No special commands needed. - -### Merging a PR to Dev - -Once approved, merge to `dev`: - -```bash -gh pr merge 123 --merge --auto -``` - -This squash-merges the PR and deletes the feature branch. To keep history with merge commits: - -```bash -gh pr merge 123 --create-branch-off-target --auto -``` - -After merge, update your local dev: - -```bash -git checkout dev -git pull origin dev -``` - ---- - -## Merging Back to Dev - -After a release ships from `main`, sync changes back to `dev` (for docs updates, changelog, version bumps made during release): - -### Step 1: Create a Sync PR - -On your `dev` branch: - -```bash -git checkout dev -git pull origin dev -git checkout -b chore/sync-from-main -``` - -Merge `main` into the sync branch: - -```bash -git merge main --no-ff --no-edit -``` - -This brings all production commits back to dev, preserving the release tag and history. - -### Step 2: Resolve Conflicts (if any) - -If conflicts exist, resolve them: - -```bash -git status -# Lists conflicted files -git add . -git commit -m "chore: resolve merge conflicts from main" -``` - -### Step 3: Push and Create PR - -```bash -git push -u origin chore/sync-from-main -gh pr create --base dev --title "chore: sync from main" --body "Bring production changes back to dev" -``` - -### Step 4: Merge Back - -```bash -gh pr merge --merge --auto -git checkout dev && git pull origin dev -``` - ---- - -## Full Release Lifecycle - -Complete journey from feature work to production tag. - -### Phase 1: Preparation (on `dev`) - -**Time:** Before release day. All features complete, all tests passing. - -1. **Update CHANGELOG.md:** - -```bash -# Edit CHANGELOG.md with new version entry -# Format: ## [X.Y.Z] — YYYY-MM-DD -# Sections: Added, Changed, Community, Deprecated, Removed, Fixed -nano CHANGELOG.md -``` - -Example entry: - -```markdown -## [0.4.0] — 2026-02-15 - -### Added -- MCP tool discovery and integration -- Plugin marketplace support -- Notification system (Trello, Teams, GitHub) -- 11 new universes (Futurama, Seinfeld, The Office, etc.) -- Branch protection guard (squad-main-guard.yml) - -### Changed -- VS Code support now fully compatible (zero code changes) -- Agent progress signals with [MILESTONE] markers -- Universe count: 20 → 31 - -### Community -- @csharpfritz: MCP tool discovery (#11), user docs (#16) -- @spboyer: VS Code compatibility (#17) -``` - -2. **Update version in package.json:** - -```bash -# Edit version field -nano package.json -# "version": "0.4.0" -``` - -3. **Commit to dev:** - -```bash -git add CHANGELOG.md package.json -git commit -m "chore: prepare release v0.4.0" -git push origin dev -``` - -### Phase 2: Preview Build (on `preview`) - -**Time:** Release day morning. Validate all files before shipping. - -Follow [Preview Build Workflow](#preview-build-workflow) above. Summary: - -```bash -git checkout preview -git reset --hard origin/dev -git rm --cached -r .ai-team/ 2>/dev/null -git rm --cached -r team-docs/ 2>/dev/null -git commit -m "chore: remove forbidden paths for preview" 2>/dev/null -git push -f origin preview -# Wait for guard workflow to pass -``` - -Check GitHub Actions: - -```bash -gh run list --branch preview --status completed --limit 1 -``` - -Expected: ✅ All checks pass. - -### Phase 3: Merge to Main (on `main`) - -**Time:** Release day afternoon, after preview validation. - -1. **Create a release PR to main:** - -```bash -git checkout main -git pull origin main -git checkout -b release/v0.4.0 -git merge --no-ff preview -m "Release v0.4.0" -git push -u origin release/v0.4.0 -``` - -2. **Create PR for final review:** - -```bash -gh pr create --base main --title "Release v0.4.0" --body "Final release PR. Guard enforces file restrictions." -``` - -3. **Wait for guard to pass**, then merge: - -```bash -gh pr merge --merge --auto -``` - -The guard validates that only distribution-safe files reach `main`. - -### Phase 4: Tag the Release (on `main`) - -**Time:** After merge to `main`. This triggers the release workflow. - -```bash -git checkout main -git pull origin main -git tag -a v0.4.0 -m "Release v0.4.0: MCP integration, Plugin marketplace, Notifications" -git push origin v0.4.0 -``` - -Tag format: `vX.Y.Z` (semantic versioning). The version MUST match `package.json` version. - -### Phase 5: Verify the Release - -The tag push triggers `.github/workflows/release.yml`: - -```bash -# Monitor the release workflow -gh run list --workflow release.yml --status in_progress -gh run list --workflow release.yml --status completed --limit 1 -``` - -Check what the workflow does: - -1. Runs full test suite -2. Creates a GitHub Release with notes -3. Validates that only distribution files were shipped - -If the workflow fails, see [Troubleshooting](#troubleshooting). - -### Phase 6: Sync Back to Dev - -After release, bring version/changelog updates back to dev: - -```bash -git checkout dev -git pull origin dev -git checkout -b chore/sync-from-main -git merge main --no-ff -git push -u origin chore/sync-from-main -gh pr merge --merge --auto -git pull origin dev -``` - ---- - -## Branch Protection Rules - -The repository enforces protection rules on `main` and `preview` to prevent accidental shipping of forbidden files. - -### What's Protected - -| Branch | Rule | Effect | -|--------|------|--------| -| `main` | Require PR review | All PRs require at least 1 approval | -| `main` | Require status checks to pass | Tests must pass before merge allowed | -| `preview` | Require status checks to pass | Tests must pass before merge allowed | - - -## File Integrity - -Always verify before pushing to main or preview that you have not accidentally included team runtime state files (.squad/, .ai-team/, etc.). These files should only exist on dev branches. - ---- - -## Troubleshooting - -### Issue: Forbidden Files Detected in PR - -**Problem:** You accidentally committed `.ai-team/` or other team state files to your PR. - -**Prevention:** Use `.gitignore` rules and verify `git status` before pushing: - -```bash -# Check what will be committed -git status - -# If you see .ai-team/ or similar, remove it: -git rm --cached -r .ai-team/ -git commit -m "chore: remove runtime state files" -git push -``` - ---- - -### Issue: SSH Hangs During Push - -**Symptom:** `git push` hangs indefinitely. - -**Cause:** SSH authentication timeout or network issue. - -**Fix:** - -```bash -# Try with HTTP instead (if you have auth configured) -git remote set-url origin https://github.com/bradygaster/squad.git -git push origin - -# Or explicitly use SSH with a shorter timeout -GIT_SSH_COMMAND="ssh -v" git push origin - -# If still stuck, check your SSH key -ssh -T git@github.com -``` - ---- - -### Issue: .ai-team/ Files Keep Getting Committed - -**Symptom:** `.ai-team/` shows as untracked but somehow appears in commits. - -**Cause:** Files were previously tracked (added with `git add -f` before `.gitignore` was updated). - -**Fix:** Remove tracked copies permanently (one time per repo): - -```bash -# Remove .ai-team/ from git tracking -git rm --cached -r .ai-team/ - -# Verify .gitignore has .ai-team/ -grep ".ai-team" .gitignore - -# If not, add it -echo ".ai-team/" >> .gitignore - -# Commit -git add .gitignore -git commit -m "chore: ensure .ai-team/ is untracked" -git push origin dev -``` - ---- - -### Issue: Missing Workflows in .github/workflows/ - -**Symptom:** Other Squad workflows are missing or accidentally deleted. - -**Cause:** Workflows not installed during Squad init, or accidentally deleted. - -**Fix:** Re-run upgrade to restore workflows: - -```bash -npx github:bradygaster/squad upgrade -git add .github/workflows/ -git commit -m "chore: restore Squad workflows" -git push origin dev -``` - -Available Squad workflows: -- `squad-heartbeat.yml` — Ralph's periodic triage and labeling -- `squad-issue-assign.yml` — Auto-assign labeled issues -- `squad-label-enforce.yml` — Enforce label namespace integrity -- `squad-triage.yml` — Triage unlabeled issues -- `sync-squad-labels.yml` — Sync static label definitions - ---- - -### Issue: GitHub Release Not Created After Tag - -**Symptom:** Tag pushed but no GitHub Release appears. - -**Cause:** Release workflow failed, or release already exists for that tag. - -**Fix:** - -```bash -# Check workflow status -gh run list --workflow release.yml --status completed --limit 1 - -# View the latest run details -gh run view - -# If the workflow failed, check logs -gh run view --log - -# If no release exists, create manually -gh release create v0.4.0 --title "v0.4.0" \ - --notes-file CHANGELOG.md - -# To set as prerelease (for 0.x versions) -gh release create v0.4.0 --title "v0.4.0" --prerelease \ - --notes-file CHANGELOG.md -``` - ---- - -## Sample Prompts - -Use these with Kobayashi or in Copilot sessions to guide release work. - -### To Prepare for Release - -``` -Kobayashi, prepare v0.4.0 for release: -1. Update CHANGELOG.md with the new version entry -2. Update version in package.json -3. Commit both changes to dev branch - -Use these features as the new entry: -- MCP tool discovery and integration -- Plugin marketplace support -- Notification system -- 11 new universes -- Branch protection guard -``` - -### To Build a Preview - -``` -Kobayashi, build a preview branch: -1. Create preview branch from dev -2. Remove .ai-team/ and team-docs/ (except blog) -3. Commit the removal -4. Push to origin -5. Wait for guard workflow to pass -6. Confirm the guard result -``` - -### To Tag a Release - -``` -Kobayashi, tag the release: -1. Checkout main -2. Create and push tag v0.4.0 -3. Verify the release workflow starts -4. Report when it completes -``` - -### To Sync After Release - -``` -Kobayashi, sync main back to dev: -1. Create a chore/sync-from-main branch -2. Merge main into it -3. Create and merge PR back to dev -4. Confirm dev is up to date -``` - -### To Test the Guard - -``` -Kobayashi, test the guard workflow: -1. Create a test branch test/guard-ai-team-block -2. Add .ai-team/agents/test/history.md with dummy content -3. Commit and push -4. Create PR to main -5. Report the guard result (should fail) -6. Remove the file and push again -7. Report the final guard result (should pass) -8. Clean up the branch -``` - -### To Fix a Blocked PR - -``` -Kobayashi, fix this blocked PR: -1. Fetch the current PR state -2. Remove all .ai-team/ and team-docs/ files -3. Commit the removal -4. Push to update the PR -5. Wait for guard to pass -``` - ---- - -## Key Files Reference - -- **Release workflow:** `.github/workflows/release.yml` (if it exists) -- **Changelog:** `CHANGELOG.md` -- **Distribution config:** `package.json` (version, files array) -- **Ignore rules:** `.gitignore`, `.npmignore`, `.gitattributes` -- **Branch protection settings:** GitHub repo Settings → Branches -- **Distributed via:** `npx github:bradygaster/squad` - ---- - -## Tips - -- **Preview is your staging environment.** Test everything there before merging to main. -- **Guard is your safety net.** Let it block forbidden files—it's preventing distribution corruption. -- **`.ai-team/` never leaves dev.** It's runtime state, not product. -- **Tag from main only.** This is your single source of truth for releases. -- **Version in package.json must match git tag.** Keep them in sync. -- **Communicate releases.** Update team.md, decisions.md, and CHANGELOG.md before shipping. -- **Use `gh` CLI for everything.** It's faster and more reliable than web UI for scripting. - diff --git a/docs/scenarios/troubleshooting.md b/docs/scenarios/troubleshooting.md deleted file mode 100644 index 89763683f..000000000 --- a/docs/scenarios/troubleshooting.md +++ /dev/null @@ -1,124 +0,0 @@ -# Troubleshooting - -Common issues and fixes for Squad installation and usage. - ---- - -## `npx github:bradygaster/squad` appears to hang - -**Problem:** Running the install command shows a frozen npm spinner. Nothing happens. - -**Cause:** npm resolves `github:` package specifiers via `git+ssh://git@github.com/...`. If no SSH agent is running (or your key isn't loaded), git prompts for your passphrase on the TTY — but npm's progress spinner overwrites the prompt, making it invisible. This is an npm TTY handling issue, not a Squad bug. - -**Fix (choose one):** - -1. **Start your SSH agent first** (recommended): - ```bash - eval "$(ssh-agent -s)" - ssh-add - ``` - Then re-run `npx github:bradygaster/squad`. - -2. **Disable npm's progress spinner** to reveal the prompt: - ```bash - npx --progress=false github:bradygaster/squad - ``` - -3. **Use HTTPS instead of SSH** by configuring git: - ```bash - git config --global url."https://github.com/".insteadOf git@github.com: - ``` - -**Reference:** [#30](https://github.com/bradygaster/squad/issues/30) - ---- - -## `gh` CLI not authenticated - -**Problem:** GitHub Issues, PRs, Ralph, or Project Boards commands fail with authentication errors. - -**Cause:** The `gh` CLI isn't logged in, or is missing required scopes. - -**Fix:** - -1. Log in: - ```bash - gh auth login - ``` - -2. If using Project Boards, add the `project` scope: - ```bash - gh auth refresh -s project - ``` - -3. Verify: - ```bash - gh auth status - ``` - ---- - -## Node.js version too old - -**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`). - -**Fix:** - -```bash -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` -- **Direct download:** [nodejs.org](https://nodejs.org/) - ---- - -## Squad agent not appearing in Copilot - -**Problem:** After install, `squad` doesn't show up in the `/agent` (CLI) or `/agents` (VS Code) list in GitHub Copilot. - -**Cause:** The `.github/agents/squad.agent.md` file may not have been created, or Copilot hasn't refreshed its agent list. - -**Fix:** - -1. Verify the file exists: - ```bash - ls .github/agents/squad.agent.md - ``` - If missing, re-run `npx github:bradygaster/squad`. - -2. Restart your Copilot session — close and reopen the terminal or editor. - ---- - -## Upgrade doesn't change anything - -**Problem:** Running `npx github:bradygaster/squad upgrade` completes but nothing changes. - -**Cause:** You may already be on the latest version, or npm cached an old version. - -**Fix:** - -1. Check current version in `.github/agents/squad.agent.md` (frontmatter `version:` field). - -2. Clear npm cache and retry: - ```bash - npx --yes github:bradygaster/squad upgrade - ``` - ---- - -## Windows-specific issues - -**Problem:** Path errors or file operations fail on Windows. - -**Cause:** Some shell commands assume Unix-style paths. - -**Fix:** Squad's core uses `path.join()` for all file operations and is Windows-safe. If you see path issues: -- Use PowerShell or Git Bash (not cmd.exe) -- Ensure git is in your PATH -- Ensure `gh` CLI is in your PATH 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..e7ffa8e88 --- /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..a50e168a9 --- /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..cac07914b --- /dev/null +++ b/docs/src/components/Search.astro @@ -0,0 +1,193 @@ +--- +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..a631d562c --- /dev/null +++ b/docs/src/components/Sidebar.astro @@ -0,0 +1,80 @@ +--- +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 82% rename from docs/concepts/github-workflow.md rename to docs/src/content/docs/concepts/github-workflow.md index 905f1f44b..968a9419e 100644 --- a/docs/concepts/github-workflow.md +++ b/docs/src/content/docs/concepts/github-workflow.md @@ -47,6 +47,32 @@ Connect repo → Show backlog → Assign issues → Agent branches + imple --- +## Working with your team + +Squad is built for mixed teams — humans set direction, AI agents execute and report back. The Lead agent bridges between them, routing work and surfacing decisions when a human needs to act. + +### Humans in the lifecycle + +The following is **one example** of how a mixed team might divide responsibilities. Your team decides its own process — use [ceremonies](../features/ceremonies.md) and [directives](../features/human-team-members.md) to shape the workflow that fits. + +| Stage | Who acts | What happens | +|-------|----------|--------------| +| **Triage** | Human (or Lead) | Applies `go:yes` / `go:no` — decides what's worth building | +| **Design review** | Human + team | Auto-triggered ceremony before multi-agent work; humans can participate or observe | +| **Implementation** | AI agents | Branch, build, test, open PRs — no human input required | +| **PR review** | Human | Reviews and approves (or requests changes); lockout protocol prevents conflicting edits | +| **Merge** | Human or Ralph | Squash-merge, branch cleanup, issue closed | + +This is a starting point. Define your own checkpoints by configuring [ceremonies](../features/ceremonies.md) and capturing [directives](../features/human-team-members.md). + +For details on how work routes to humans, see [Human team members](../features/human-team-members.md). + +For ceremony details, see [Ceremonies](../features/ceremonies.md). + +For agent anatomy and how each team member (AI, human, @copilot) is structured, see [your-team.md](your-team.md). + +--- + ## Label Taxonomy Labels aren't just tags — they're Squad's **state machine**. Five namespaces drive workflow automation, routing, and lifecycle tracking. @@ -175,18 +201,7 @@ Board sync runs on label changes, issue close, PR merge, and a 30-minute schedul Your squad pings you when they need input, hit an error, or finish work. Squad uses MCP-based notification servers — you bring your own delivery channel. -The flow: -1. **Skill** (`human-notification`) tells agents when to ping -2. **Agent** invokes your configured MCP server -3. **MCP server** (Teams, Discord, iMessage, webhook) delivers the message - -| Trigger | Example | -|---------|---------| -| Blocked on input | "Keaton needs your decision on the API approach" | -| Error hit | "McManus got an auth error — needs credentials" | -| Work complete | "Fenster finished the test suite — 142 tests passing" | - -Configure in `.vscode/mcp.json` or `.copilot/mcp-config.json`. See the [MCP setup section in Portability & Extensions](portability.md) for configuration details. +See the [Notifications Guide](../features/notifications.md) for [platform setup](../features/notifications.md#quick-start-teams-simplest-path) (Teams, Discord, iMessage, webhooks), [trigger configuration](../features/notifications.md#what-triggers-a-notification), and [sample MCP configs](../features/notifications.md#sample-mcp-configs). --- diff --git a/docs/concepts/memory-and-knowledge.md b/docs/src/content/docs/concepts/memory-and-knowledge.md similarity index 84% rename from docs/concepts/memory-and-knowledge.md rename to docs/src/content/docs/concepts/memory-and-knowledge.md index 27643cfa2..4b985840d 100644 --- a/docs/concepts/memory-and-knowledge.md +++ b/docs/src/content/docs/concepts/memory-and-knowledge.md @@ -210,6 +210,27 @@ Skills export and import with your team. Move a trained team to a new repo, and --- +## Knowledge persistence + +Not all knowledge in `.squad/` lasts forever. When files grow large, Squad compacts them to keep performance fast. Here's what persists and what gets summarized: + +| What | File | Compacted? | Where old content goes | Who reads it | +|------|------|-----------|----------------------|-------------| +| Personal history | `history.md` | Yes, at ~12 KB | `history-archive.md` (preserved, read-only) | Owning agent | +| Shared decisions | `decisions.md` | Yes, when large | `decisions-archive.md` (preserved, not loaded) | All agents | +| Skills | `skills/{name}/SKILL.md` | Never | Grows indefinitely | All agents | +| Directives | In `decisions.md` | With decisions | Archived with decisions | All agents | +| Wisdom | `identity/wisdom.md` | Never | Permanent | All agents | +| Casting registry | `casting/registry.json` | Never | Permanent | Coordinator | +| Session logs | `log/*.md` | Never edited | Append-only archive | Read-only | +| Orchestration logs | `orchestration-log/*.md` | Never edited | Append-only archive | Read-only | + +Knowledge that needs to survive compaction belongs in **skills**. Reusable patterns, code conventions, and technical techniques live here because they grow without limits. Team rules and preferences go in directives (stored in `decisions.md`) — they persist through compaction cycles because directives are preserved when decisions get summarized. + +> 💡 **Where to store permanent knowledge:** Put reusable patterns and techniques in `.squad/skills/`. Put team rules and preferences in directives (they persist in `decisions.md`). For org-wide knowledge that multiple teams need, use [upstream inheritance](/features/upstream-inheritance) to share a skills library. + +--- + ## Tips - **Commit `.squad/`** — anyone who clones the repo gets the team with all their accumulated knowledge. 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 99% rename from docs/concepts/portability.md rename to docs/src/content/docs/concepts/portability.md index 4636e1fde..457109c97 100644 --- a/docs/concepts/portability.md +++ b/docs/src/content/docs/concepts/portability.md @@ -236,7 +236,7 @@ MCP (Model Context Protocol) servers extend Squad with external services. Agents "mcpServers": { "github": { "command": "node", - "args": ["/path/to/github-mcp.js"], + "args": ["/absolute/path/to/github-mcp.js"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/docs/concepts/your-team.md b/docs/src/content/docs/concepts/your-team.md similarity index 69% rename from docs/concepts/your-team.md rename to docs/src/content/docs/concepts/your-team.md index 6811cd886..64d586d13 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 @@ -212,18 +214,84 @@ Squad auto-selects the right level of effort for each request: | `"Remove McManus from the team"` | Archives agent directory to `.squad/agents/.archived/`, updates team.md | | `"Change the tester to focus on integration tests"` | Updates the tester's charter and expertise | | `"Route all CSS files to Frontend"` | Adds a rule to `.squad/routing.md` | -| `"From now on, McManus reviews all docs before merge"` | Creates routing rule + [directive](memory-and-knowledge.md) | +| `"From now on, McManus reviews all docs before merge"` | Creates routing rule + [directive](../features/memory.md) | Running `init` on an existing Squad repo automatically offers upgrade mode. --- +## Planning your team + +Before running `squad init`, think through these decisions. Squad will scan your repo and propose a team — having answers ready makes setup faster. + +- **What does your project do?** Have a 1–2 sentence description of the language, stack, and purpose ready — Squad uses this to pick roles +- **What roles do you need?** The [default composition](#default-team-composition) covers common cases, or let Squad propose custom roles based on your repo +- **How many agents?** Typical teams are 3–7 agents. Scribe (memory) is always included +- **Will humans join the team?** [Human members](#human-team-members) can serve as reviewers or domain experts alongside AI agents +- **Will @copilot participate?** The GitHub Copilot coding agent can pick up issues autonomously — see [Agent anatomy](#agent-anatomy) +- **How will you track work?** GitHub Issues with `squad:{member}` labels, or conversational tasking via named prompts +- **Do you want review gates?** [Reviewers](#reviewer-protocol) can approve or reject work before it proceeds +- **What ceremonies matter?** [Design reviews and retrospectives](#ceremonies) can auto-trigger or run on demand +- **What model preferences?** Default is automatic selection, or specify preferred models per agent — see [Parallel Work & Models](parallel-work.md) +- **How many squads, and where do they live?** One squad per repo is the default — your `.squad/` directory lives alongside your code. For multi-repo projects, you can run one squad per repo (each with its own team) or share a single squad across repos using a personal squad or linked team repo. Start with one squad in one repo and expand as needed. + +--- + +## Agent anatomy + +An agent is a directory at `.squad/agents/{name}/`. The contents depend on the member type. + +For how humans differ from AI agents, see [Human team members](#human-team-members) above. + +| | @copilot (🤖) | +|---|---| +| Directory | None | +| `charter.md` | ❌ Uses `copilot-instructions.md` | +| `history.md` | ❌ | +| Spawnable | ❌ Works via issue assignment | + +**AI agents** have a `charter.md` (identity, expertise, voice — compiled into the system prompt at spawn time) and an optional `history.md` (append-only cross-session learnings). + +**@copilot** (🤖) appears on the roster and works via GitHub issue assignment. It reads `.github/copilot-instructions.md` instead of a charter. + +**Retired agents** move to `.squad/agents/_alumni/{name}/` — charter preserved as a read-only archive, not spawnable. + +--- + +## Cross-agent context + +Agents don't share memory directly. Context flows through explicit shared files: + +- **`team.md`** — who's on the team and what they do +- **`routing.md`** — work assignment rules the coordinator reads on every request +- **`decisions.md`** — canonical team memory: directives, patterns, learnings +- **`.squad/decisions/inbox/`** — agents drop decision files here; the Scribe merges them into `decisions.md` + +Each agent's `history.md` is personal — only that agent reads it at spawn time. For the full picture on knowledge flow, see [Memory and knowledge](../features/memory.md). + +--- + +## Hiring an agent + +To add a new AI agent to your team: + +- [ ] Create `.squad/agents/{name}/` directory +- [ ] Write `charter.md` — start from `.squad/templates/charter.md` +- [ ] Add to `team.md` roster with status `✅ Active` +- [ ] Add to `routing.md` with work type assignments +- [ ] (Optional) Create `history.md` for persistent memory +- [ ] (Optional) Allocate a name via the casting system + +To add a **human member**, skip the directory — just add them to `team.md`. See [Human team members](#human-team-members) for badge and routing details. + +--- + ## Tips - **Commit `.squad/`** to version control — anyone who clones the repo gets the full team with all accumulated knowledge. - Use human members for approval gates: design review, compliance, final sign-off. - Design reviews prevent agents from building conflicting implementations — let them run on multi-agent tasks. -- Retros produce [decisions](memory-and-knowledge.md) that improve future work, not just diagnose the current failure. +- Retros produce [decisions](../features/memory.md) that improve future work, not just diagnose the current failure. - You're the relay for human members. Squad can't message them directly — it tells you, and you coordinate. --- 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/src/content/docs/features/built-in-roles.md b/docs/src/content/docs/features/built-in-roles.md new file mode 100644 index 000000000..769088e48 --- /dev/null +++ b/docs/src/content/docs/features/built-in-roles.md @@ -0,0 +1,95 @@ +# Built-in Base Roles + +## Overview + +- Squad ships with 20 curated base roles covering software development and business operations. +- Base roles provide deep, substantive charter content out of the box — no LLM generation needed. +- During team casting, base roles serve as starting points that get refined for your project context. +- Role content is adapted from [agency-agents](https://github.com/msitarzewski/agency-agents) by AgentLand Contributors (MIT License). + +## Why Base Roles? + +- **Faster setup** — deterministic role selection instead of LLM improvisation. +- **Lower token cost** — base content provides 90% of the charter; only project-specific refinement needs the LLM. +- **Higher quality** — curated expertise, boundaries, and voice instead of generic boilerplate. +- **Broad coverage** — not just software dev; marketing, sales, product, game dev, and more. + +## Software Development Roles (12) + +| Emoji | ID | Title | Vibe | +|-------|----|-------|------| +| 🏗️ | `lead` | Lead / Architect | Designs systems that survive the team that built them. Every decision has a trade-off — name it. | +| ⚛️ | `frontend` | Frontend Developer | Builds responsive, accessible web apps with pixel-perfect precision. | +| 🔧 | `backend` | Backend Developer | Designs the systems that hold everything up — databases, APIs, cloud, scale. | +| 💻 | `fullstack` | Full-Stack Developer | Sees the full picture — from the database to the pixel. | +| 👁️ | `reviewer` | Code Reviewer | Reviews code like a mentor, not a gatekeeper. Every comment teaches something. | +| 🧪 | `tester` | Test Engineer | Breaks your API before your users do. | +| ⚙️ | `devops` | DevOps Engineer | Automates infrastructure so your team ships faster and sleeps better. | +| 🔒 | `security` | Security Engineer | Models threats, reviews code, and designs security architecture that actually holds. | +| 📊 | `data` | Data Engineer | Thinks in tables and queries. Normalizes first, denormalizes when the numbers demand it. | +| 📝 | `docs` | Technical Writer | Turns complexity into clarity. If the docs are wrong, the product is wrong. | +| 🤖 | `ai` | AI / ML Engineer | Builds intelligent systems that learn, reason, and adapt. | +| 🎨 | `designer` | UI/UX Designer | Pixel-aware and user-obsessed. If it looks off by one, it is off by one. | + +## Business & Operations Roles (8) + +| Emoji | ID | Title | Vibe | +|-------|----|-------|------| +| 📣 | `marketing-strategist` | Marketing Strategist | Drives growth through content and channels — every post has a purpose. | +| 💼 | `sales-strategist` | Sales Strategist | Closes deals with strategic precision — understand the buyer before pitching the solution. | +| 📋 | `product-manager` | Product Manager | Shapes what gets built and why — every feature earns its place. | +| 📅 | `project-manager` | Project Manager | Keeps the train on the tracks — scope, schedule, and sanity. | +| 🎧 | `support-specialist` | Support Specialist | First line of defense for users — solve fast, document everything. | +| 🎮 | `game-developer` | Game Developer | Builds worlds players want to live in — every mechanic serves the experience. | +| 📺 | `media-buyer` | Media Buyer | Maximizes ROI across ad channels — every dollar tracked, every impression measured. | +| ⚖️ | `compliance-legal` | Compliance & Legal | Ensures you ship safely and legally — compliance is a feature, not a blocker. | + +## Using Base Roles + +### During Init + +```bash +$ squad init +What are you building? > A React + Node.js API with Stripe integration + +Suggested team: + 🏗️ Lead / Architect + ⚛️ Frontend Developer + 🔧 Backend Developer + 🧪 Test Engineer + +Look right? [Yes] [Add someone] [Change a role] [Browse all roles] +``` + +### In squad.config.ts (SDK Mode) + +```typescript +import { useRole, defineSquad } from '@bradygaster/squad-sdk'; + +export default defineSquad({ + agents: [ + useRole('lead', { name: 'ripley' }), + useRole('frontend', { name: 'dallas' }), + useRole('backend', { name: 'kane', expertise: ['Node.js', 'PostgreSQL', 'Stripe API'] }), + useRole('tester', { name: 'lambert' }), + ], +}); +``` + +### CLI: Browse Roles + +```bash +$ squad roles # list all 20 roles +$ squad roles --category engineering # filter by category +$ squad roles --search "security" # search by keyword +``` + +## Customization + +- Override expertise, style, voice, or boundaries via `useRole()` options. +- Add extra ownership or approach items with `extraOwnership`/`extraApproach`. +- Base roles are starting points — the coordinator refines them for your project context during casting. + +## Attribution + +Built-in role content is adapted from [agency-agents](https://github.com/msitarzewski/agency-agents) by AgentLand Contributors, released under the MIT License. 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/src/content/docs/features/context-hygiene.md b/docs/src/content/docs/features/context-hygiene.md new file mode 100644 index 000000000..bef518244 --- /dev/null +++ b/docs/src/content/docs/features/context-hygiene.md @@ -0,0 +1,130 @@ +# Context Hygiene: Nap, Reskill, and Compact + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + + +**Try this to compact your team's memory:** +``` +Team, take a nap +``` + +**Try this to refresh agent skills:** +``` +Team, reskill +``` + +**Try this to do both and report results:** +``` +Team, reskill, take a nap, and let me know how much context you cleared out collectively for future iterations +``` + +Over multiple sessions, Squad's `.squad/` files grow — agent histories, decisions, skill files. Context hygiene commands let you actively manage that growth so agents stay fast and focused. + +--- + +## Nap + +**What it does:** Summarizes accumulated work into smaller, more efficient memory files. This is the same as running `/compact` in the CLI or `squad nap` from the command line. + +When you tell the team to "take a nap," each agent: + +1. Reviews its `history.md` and other state files +2. Compresses older entries into concise summaries +3. Archives verbose detail while preserving key decisions and learnings +4. Reports how much context was reclaimed + +### Nap ≠ Shutting Down + +This is the most common misconception: + +| Action | What happens to `.squad/` files | +|--------|-------------------------------| +| **Shutting down Squad** (closing the CLI, killing the process) | Files stay exactly as they are. Nothing is summarized or compacted. | +| **Nap** (`team, take a nap` or `squad nap`) | Files are actively summarized and compacted. Older entries are archived, working context gets leaner. | + +Shutting down Squad every night does **not** perform context hygiene. You must explicitly tell the team to take a nap. + +### CLI equivalents + +```bash +squad nap # Standard context hygiene +squad nap --deep # Thorough cleanup with recursive descent +squad nap --dry-run # Preview what would be cleaned up +``` + +In the interactive shell, use `/compact` for the same effect. + +--- + +## Reskill + +**What it does:** Tells agents to re-examine their skills, validate them against the current codebase, and potentially discover new patterns. + +When you tell the team to "reskill," agents: + +1. Review existing skill files in `.squad/skills/` +2. Validate that documented patterns still apply +3. Look for new reusable patterns from recent work +4. Update skill confidence levels based on current evidence + +### Availability + +> **Note:** As of now, reskill requires running Squad from source (via symlink). It is not yet available through `squad upgrade`. This will change in a future release. + +--- + +## Combined Commands + +You can trigger nap and reskill together in a single prompt: + +``` +Team, reskill, take a nap, and let me know how much context you cleared out collectively for future iterations +``` + +This runs both behaviors and gives you a report on how much context was reduced — useful for understanding how lean your team's working memory is before the next session. + +--- + +## When to Use These + +| Situation | Command | +|-----------|---------| +| After several work sessions, agents feel slow or unfocused | `team, take a nap` | +| Codebase has changed significantly and skills may be stale | `team, reskill` | +| Before a major new phase of work | Combine both | +| End of sprint / milestone | `squad nap --deep` | + +--- + +## Tips + +- **Nap regularly.** A few sessions of heavy work can bloat history files. Napping keeps context budgets in check. +- **Don't rely on shutdown.** Closing the CLI preserves files as-is — it does not compact anything. +- **Reskill after refactors.** If you've restructured the codebase, agent skills may reference outdated patterns. +- **Check the dry run first.** Use `squad nap --dry-run` to preview cleanup actions before committing to them. + +## Sample Prompts + +``` +team, take a nap +``` + +Compacts and summarizes all agent memory files, reclaiming context space. + +``` +team, reskill +``` + +Agents re-examine and validate their skills against the current codebase. + +``` +team, reskill, take a nap, and let me know how much context you cleared out collectively for future iterations +``` + +Combines both behaviors and reports back on total context reduction. + +``` +squad nap --dry-run +``` + +Previews what a nap would clean up without making any changes. diff --git a/docs/features/copilot-coding-agent.md b/docs/src/content/docs/features/copilot-coding-agent.md similarity index 94% rename from docs/features/copilot-coding-agent.md rename to docs/src/content/docs/features/copilot-coding-agent.md index 8cb0a8b6a..f9b10bba8 100644 --- a/docs/features/copilot-coding-agent.md +++ b/docs/src/content/docs/features/copilot-coding-agent.md @@ -33,8 +33,11 @@ gh secret set COPILOT_ASSIGN_TOKEN git add .github/ .squad/ && git commit -m "feat: add copilot to squad" && git push # 5. Test — label any issue with squad:copilot +gh issue edit --add-label "squad:copilot" ``` +> **Why can't I use `gh issue edit --add-assignee "@copilot"`?** Bot accounts cannot be assigned via the GitHub CLI the same way as human users. Use label-based assignment instead. See [FAQ: Why doesn't gh issue edit --add-assignee "@copilot" work?](../guide/faq.md#why-doesnt-gh-issue-edit---add-assignee-copilot-work) for details. + --- ## Enabling @copilot diff --git a/docs/src/content/docs/features/cost-tracking.md b/docs/src/content/docs/features/cost-tracking.md new file mode 100644 index 000000000..13b638421 --- /dev/null +++ b/docs/src/content/docs/features/cost-tracking.md @@ -0,0 +1,89 @@ +# Token Usage & Cost Tracking + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +Squad can track token usage and estimated cost for each agent spawn, roll that data up by session, and expose it through orchestration logs, terminal summaries, and telemetry backends. + +--- + +## Overview + +- Squad tracks token usage (input/output tokens) and estimated cost per agent spawn +- Usage data is recorded in orchestration logs and available via `squad cost` CLI +- Optional budget limits can be configured per agent or per session + +--- + +## How It Works + +- The `CostTracker` class (`packages/squad-sdk/src/runtime/cost-tracker.ts`) accumulates token data +- Each orchestration log entry includes a **Token usage** row +- OTel metrics (`squad.tokens.input`, `squad.tokens.output`, `squad.tokens.cost`) are emitted when telemetry is enabled + +The orchestration log template stores usage in a markdown table row like this: + +```md +| **Token usage** | 12,450 in / 3,200 out — $0.0234 | +``` + +--- + +## Viewing Costs + +```bash +squad cost # current session costs +squad cost --all # all historical costs +squad cost --agent fenster # costs for specific agent +``` + +**Example output:** + +```text +=== Squad Cost Summary === +Total input tokens: 12,450 +Total output tokens: 3,200 +Estimated cost: $0.0234 + +--- By Agent --- + fenster: 12,450in / 3,200out ($0.0234) [1 turns, model: claude-sonnet-4.5] + +--- By Session --- + session-abc123: 12,450in / 3,200out ($0.0234) [1 turns] +``` + +--- + +## Budget Configuration + +```typescript +import { defineSquad, defineAgent, defineBudget } from '@bradygaster/squad-sdk'; + +export default defineSquad({ + defaults: { + budget: defineBudget({ + perAgentSpawn: 50000, + perSession: 500000, + warnAt: 0.8, + }), + }, + agents: [ + defineAgent({ + name: 'fenster', + role: 'Core Dev', + budget: defineBudget({ perAgentSpawn: 100000 }), + }), + ], +}); +``` + +- `perAgentSpawn` limits an individual agent invocation +- `perSession` limits the total budget for the coordinator session +- `warnAt` emits warnings when usage reaches a fraction of the configured limit + +--- + +## OTel Integration + +- Token metrics are exported as OpenTelemetry counters when telemetry is enabled +- Compatible with Aspire dashboard, Grafana, and any OTel-compatible backend +- Metrics: `squad.tokens.input`, `squad.tokens.output`, `squad.tokens.cost` 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..33b6d7a21 --- /dev/null +++ b/docs/src/content/docs/features/distributed-mesh.md @@ -0,0 +1,318 @@ +# 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. + +--- + +## Skill scope + +When you ask an agent to set up a distributed mesh, the skill produces three things: + +1. **`mesh.json` config file** — defines squads, zones, and sync sources +2. **A decision entry** — records why you configured the mesh this way +3. **Sync scripts** — copies pre-built `sync-mesh.sh` and `sync-mesh.ps1` from the skill's bundled resources + +The skill does **not** generate: + +- ❌ Code (validators, helpers, utilities) +- ❌ Tests (the sync scripts are pre-tested templates) +- ❌ Custom sync scripts (bundled scripts are copied, not regenerated) + +**Why this matters:** Deterministic skills give you consistent results. The sync scripts are bundled with the distributed-mesh skill. Agents shouldn't waste time generating validators or rewriting sync logic from scratch — they should copy the bundled scripts and configure your `mesh.json`. + +If you need to customize the sync behavior, edit the copied scripts in your project root. The mesh skill's job ends at configuration. + +--- + +## 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..a77cd219d --- /dev/null +++ b/docs/src/content/docs/features/enterprise-platforms.md @@ -0,0 +1,176 @@ +# 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. + +For GitHub repositories, Squad uses the `gh` CLI for authentication. When working across multiple GitHub accounts (e.g., personal GitHub and Enterprise Managed Users), use `gh auth switch` to toggle between accounts. See [Cross-organization authentication](../scenarios/cross-org-auth) for detailed multi-account setup. + +Alternatively, if the Azure DevOps MCP server is configured in your environment, Squad will use it automatically for richer API access. See [MCP Setup Guide](./mcp.md#mcp-configuration-files) for configuration instructions. + +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/src/content/docs/features/issue-templates.md b/docs/src/content/docs/features/issue-templates.md new file mode 100644 index 000000000..adf5a04ad --- /dev/null +++ b/docs/src/content/docs/features/issue-templates.md @@ -0,0 +1,348 @@ +# Issue Templates for Squad + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + + +**Try this after setting up templates:** +``` +Ralph, show me untriaged issues +``` + +**Then watch Ralph auto-triage based on labels.** + +When GitHub Issues are your work queue, creating tasks should be frictionless. Issue templates pre-fill labels, structure task descriptions, and work beautifully on mobile — making it possible to add tasks in 10 seconds from anywhere. + +--- + +## Why Issue Templates Matter for Squad + +GitHub provides Issue Templates — a platform feature that pre-fills labels, fields, and structure when creating new issues. This guide shows how to configure templates that work smoothly with Squad's label-based routing. + +Squad operates best when work is captured as GitHub Issues. But creating an issue from scratch takes time: you need to remember the right labels, format the description consistently, and ensure the structure matches what agents expect. + +Issue templates solve this: + +- **Pre-filled labels** — `squad` label applied automatically +- **Structured format** — Task description, acceptance criteria, priority fields +- **Mobile-friendly** — Works in the GitHub mobile app +- **Fast task creation** — Add work while walking the dog, waiting for coffee, or during a meeting + +With templates, creating a Squad task takes 10 seconds instead of 2 minutes. + +--- + +## Basic Squad Task Template + +Create `.github/ISSUE_TEMPLATE/squad-task.yml` in your repository: + +```yaml +name: Squad Task +description: Create a task for the Squad team +title: "[Task]: " +labels: ["squad"] +body: + - type: markdown + attributes: + value: | + Thanks for creating a Squad task! Fill in the details below. + + - type: textarea + id: description + attributes: + label: Task Description + description: What needs to be done? + placeholder: | + Add dark mode support to the settings page. + + Current behavior: Settings page uses light theme only. + Expected behavior: Theme switcher in settings, respects system preference. + validations: + required: true + + - type: textarea + id: acceptance-criteria + attributes: + label: Acceptance Criteria + description: How will we know this is complete? + placeholder: | + - [ ] Theme switcher toggle added to settings + - [ ] Dark mode CSS applied when enabled + - [ ] Preference saved to localStorage + - [ ] System theme preference detected on first load + validations: + required: false + + - type: dropdown + id: priority + attributes: + label: Priority + description: How urgent is this task? + options: + - Low + - Medium + - High + - Critical + validations: + required: false +``` + +### What This Template Does + +- **Applies `squad` label** — Ralph sees it in the untriaged queue +- **Structured sections** — Description, acceptance criteria, priority +- **Markdown support** — Use checklists, code blocks, links +- **Works on mobile** — GitHub app renders forms beautifully + +--- + +## Custom Labels for Routing + +Ralph uses `.squad/routing.md` to route work to agents. Add `squad:{member}` labels to your template for pre-triaging: + +```yaml +name: Documentation Task +description: Create a docs task (auto-routed to PAO) +title: "[Docs]: " +labels: ["squad", "squad:pao"] +body: + - type: textarea + id: description + attributes: + label: What needs documenting? + placeholder: | + Add a guide for setting up Ralph in production. +``` + +When Ralph scans the board, this issue is already labeled `squad:pao` — no triage needed, work goes straight to PAO. + +### Setting up labels for Squad routing + +Create labels in your repository for each squad member: + +```bash +# Using gh CLI +gh label create "squad:pao" --description "DevRel tasks" --color "1d76db" +gh label create "squad:flight" --description "Architecture and planning" --color "d73a4a" +gh label create "squad:fido" --description "Testing and quality" --color "0e8a16" +``` + +Or use the [label sync workflow](../features/labels.md) to automate label management across repositories. + +--- + +## Template Variants + +Different work types need different structures: + +### Bug Report Template + +`.github/ISSUE_TEMPLATE/bug-report.yml`: + +```yaml +name: Bug Report +description: Report a bug for Squad to fix +title: "[Bug]: " +labels: ["squad", "bug"] +body: + - type: textarea + id: description + attributes: + label: Bug Description + description: What went wrong? + validations: + required: true + + - type: textarea + id: repro-steps + attributes: + label: Steps to Reproduce + placeholder: | + 1. Run `squad init` + 2. Create a team with 3 agents + 3. Try to export the configuration + 4. See error: "Cannot read property 'name' of undefined" + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: What should have happened? + validations: + required: false + + - type: input + id: version + attributes: + label: Squad Version + placeholder: "0.8.24" + validations: + required: false +``` + +### Feature Request Template + +`.github/ISSUE_TEMPLATE/feature-request.yml`: + +```yaml +name: Feature Request +description: Suggest a new feature for Squad +title: "[Feature]: " +labels: ["squad", "enhancement"] +body: + - type: textarea + id: problem + attributes: + label: Problem Statement + description: What problem does this feature solve? + placeholder: "As a solo developer, I want to track time spent on tasks so I can invoice clients accurately." + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: How should this feature work? + validations: + required: false + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: What other approaches did you think about? + validations: + required: false +``` + +### Doc Update Template + +`.github/ISSUE_TEMPLATE/doc-update.yml`: + +```yaml +name: Documentation Update +description: Suggest a docs improvement +title: "[Docs]: " +labels: ["squad", "squad:pao", "documentation"] +body: + - type: textarea + id: what + attributes: + label: What needs updating? + placeholder: "The Ralph deployment guide doesn't mention log rotation." + validations: + required: true + + - type: input + id: page + attributes: + label: Page URL or Path + placeholder: "docs/scenarios/ralph-operations.md" + validations: + required: false +``` + +--- + +## Mobile Workflow + +GitHub Issues + templates work from anywhere: + +**On your phone:** +1. Open GitHub app +2. Navigate to repository +3. Tap **Issues** → **New Issue** +4. Select template +5. Fill form (voice-to-text works!) +6. Tap **Submit new issue** + +**10 seconds later:** +- Issue created with `squad` label +- Ralph sees it in the next scan +- Agent picks it up autonomously + +This workflow enables "capture anywhere, process later" — add tasks while commuting, exercising, or in meetings without context-switching to a laptop. + +--- + +## Template Configuration + +GitHub supports multiple templates. Create a config file to customize the issue creation experience: + +`.github/ISSUE_TEMPLATE/config.yml`: + +```yaml +blank_issues_enabled: false +contact_links: + - name: Squad Community Discussions + url: https://github.com/bradygaster/squad/discussions + about: Ask questions or share ideas in Discussions + - name: Squad Documentation + url: https://squad.dev + about: Read the full Squad documentation +``` + +This disables blank issues (forcing template use) and provides helpful links when users click "New Issue." + +--- + +## Template Best Practices + +- **Keep templates short** — Long forms reduce completion rates +- **Make most fields optional** — Only require what's absolutely necessary +- **Use placeholders** — Show examples of good descriptions +- **Pre-fill smart defaults** — Priority: Medium, Type: Task +- **Test on mobile** — Ensure forms render well in the GitHub app +- **Use dropdown for enums** — Priority, Type, Severity (reduces typos) +- **Add markdown help** — Link to GitHub markdown guide in template + +--- + +## Integration with Ralph + +Ralph's heartbeat workflow (`.github/workflows/squad-heartbeat.yml`) scans for untriaged issues: + +1. Issue created with `squad` label (from template) +2. Heartbeat workflow runs (every 30 min or on issue create) +3. Ralph reads `.squad/routing.md` to determine agent +4. Ralph adds `squad:{member}` label +5. Next heartbeat run (or in-session Ralph) assigns agent + +If your template pre-fills `squad:{member}`, Ralph skips triage and goes straight to assignment. + +--- + +## Sample Prompts + +``` +Show me untriaged squad issues +``` + +Lists all issues with `squad` label but no `squad:{member}` assignment. + +``` +Ralph, triage and assign the backlog +``` + +Ralph reads routing rules, applies member labels, and prepares work for agents. + +--- + +## Notes + +- Templates don't prevent manual issue creation — users can still click "Open a blank issue" +- Templates are stored in `.github/ISSUE_TEMPLATE/` (note the underscore, not dash) +- Use `.yml` or `.yaml` extension (both work) +- Test templates by creating issues yourself before announcing to the team +- Mobile workflow requires GitHub app (iOS or Android) — works on tablets too + +--- + +## See Also + +- [GitHub Issues Mode](./github-issues.md) — Issue-driven development workflow +- [Ralph — Work Monitor](./ralph.md) — Ralph's work monitoring behavior +- [Labels](./labels.md) — Label management and sync workflow +- [Routing](./routing.md) — How Ralph triages work to agents 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 80% rename from docs/features/mcp.md rename to docs/src/content/docs/features/mcp.md index 4f78b4804..071111f68 100644 --- a/docs/features/mcp.md +++ b/docs/src/content/docs/features/mcp.md @@ -19,13 +19,7 @@ MCP (Model Context Protocol) servers extend Squad with external services — Git ## What MCP Means for Squad -**MCP (Model Context Protocol) servers extend your Squad environment.** Agents use MCP tools to send notifications, query GitHub, monitor deployments, integrate with Trello, and more. This guide walks you through configuring MCP services step-by-step. - ---- - -## What MCP Means for Squad - -MCP bridges Squad agents and external services. When your agents work, they can call any MCP-exposed tool — send notifications, check project status, update boards, or fetch live data. You define which services are available; agents discover and use them automatically. +MCP bridges Squad agents and external services. Agents use MCP tools to send notifications, query GitHub, monitor deployments, integrate with Trello, and more. You define which services are available; agents discover and use them automatically. --- @@ -72,7 +66,7 @@ Paste this base structure: "mcpServers": { "github": { "command": "node", - "args": ["path/to/github-mcp.js"], + "args": ["/absolute/path/to/github-mcp.js"], "env": { "GITHUB_TOKEN": "your-github-token-here" } @@ -81,7 +75,7 @@ Paste this base structure: } ``` -Replace `path/to/github-mcp.js` with the actual path to your MCP server script. The `env` object passes environment variables to the server. +Replace `/absolute/path/to/github-mcp.js` with the actual path to your MCP server script. The `env` object passes environment variables to the server. ### Step 3: Add your GitHub token @@ -145,7 +139,7 @@ Click **"Edit in settings.json"** to see the raw configuration: "copilot.mcp.servers": { "github": { "command": "node", - "args": ["path/to/github-mcp.js"], + "args": ["/absolute/path/to/github-mcp.js"], "env": { "GITHUB_TOKEN": "${env:GITHUB_TOKEN}" } @@ -153,7 +147,7 @@ Click **"Edit in settings.json"** to see the raw configuration: } ``` -The `${env:GITHUB_TOKEN}` syntax reads from your shell environment. +The `${env:GITHUB_TOKEN}` syntax reads from your shell environment. Replace `/absolute/path/to/github-mcp.js` with the actual path to your MCP server script. ### Step 4: Add environment variables @@ -182,7 +176,7 @@ Most Squad installs come with GitHub MCP pre-configured. Here's what it looks li "mcpServers": { "github": { "command": "node", - "args": ["/path/to/github-mcp.js"], + "args": ["/absolute/path/to/github-mcp.js"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } @@ -191,6 +185,8 @@ Most Squad installs come with GitHub MCP pre-configured. Here's what it looks li } ``` +Replace `/absolute/path/to/github-mcp.js` with the actual path to your GitHub MCP server script. + ### VS Code: `.vscode/settings.json` ```json @@ -198,7 +194,7 @@ Most Squad installs come with GitHub MCP pre-configured. Here's what it looks li "copilot.mcp.servers": { "github": { "command": "node", - "args": ["/path/to/github-mcp.js"], + "args": ["/absolute/path/to/github-mcp.js"], "env": { "GITHUB_TOKEN": "${env:GITHUB_TOKEN}" } @@ -207,14 +203,14 @@ Most Squad installs come with GitHub MCP pre-configured. Here's what it looks li } ``` +Replace `/absolute/path/to/github-mcp.js` with the actual path to your GitHub MCP server script. + **What it does:** -- List issues, PRs, and branches in your repo +- List issues, PRs, and branches - Create, update, and search issues -- Fetch commit history and diff info +- Fetch commit history and diffs - Post and edit PR comments -Agents automatically discover these tools and use them during work. - --- ## Example: Trello MCP @@ -228,14 +224,23 @@ Trello MCP lets agents interact with your Trello boards — create cards, move t 3. Click "Tokens" and generate a new token (grant read/write permissions) 4. Copy the **Token** -### Step 2: Add to `.copilot/mcp-config.json` +### Step 2: Add to your MCP config +Add the Trello server configuration (see [MCP Configuration Files](#mcp-configuration-files) for CLI vs VS Code): + +| Variable | How to Get It | +|----------|---------------| +| `TRELLO_API_KEY` | Visit https://trello.com/app-key | +| `TRELLO_TOKEN` | Click "Tokens" on the API key page, generate with read/write permissions | +| `TRELLO_BOARD_ID` | Open any card, get ID from URL: `trello.com/c/{{CARD_ID}}/{{BOARD_ID}}/` | + +**Config template:** ```json { "mcpServers": { "trello": { "command": "node", - "args": ["/path/to/trello-mcp.js"], + "args": ["/absolute/path/to/trello-mcp.js"], "env": { "TRELLO_API_KEY": "your-api-key", "TRELLO_TOKEN": "your-token", @@ -246,6 +251,8 @@ Trello MCP lets agents interact with your Trello boards — create cards, move t } ``` +Replace `/absolute/path/to/trello-mcp.js` with the actual path to your Trello MCP server script. + Find your **board ID** by opening any card on Trello and looking at the URL: `trello.com/c/{{CARD_ID}}/{{BOARD_ID}}/`. ### Step 3: Test it @@ -262,20 +269,15 @@ Agents will now automatically propose Trello tasks for tracking work items. ## Example: Aspire Dashboard MCP (Deployment Monitoring) -For projects using .NET Aspire, the Aspire Dashboard MCP lets agents monitor deployments, check service health, and log errors. - -### Step 1: Start Aspire Dashboard - -Your project should have a dashboard running (usually `http://localhost:18888`). - -### Step 2: Configure MCP +For .NET Aspire projects, configure the Aspire Dashboard MCP for deployment monitoring: +**Config template:** ```json { "mcpServers": { "aspire": { "command": "node", - "args": ["/path/to/aspire-mcp.js"], + "args": ["/absolute/path/to/aspire-mcp.js"], "env": { "ASPIRE_URL": "http://localhost:18888", "ASPIRE_API_KEY": "optional-api-key" @@ -285,6 +287,8 @@ Your project should have a dashboard running (usually `http://localhost:18888`). } ``` +Replace `/absolute/path/to/aspire-mcp.js` with the actual path to your Aspire MCP server script. + ### Step 3: Use it Agents can now ask: @@ -320,9 +324,9 @@ Agents don't need special setup to discover tools. Here's the flow: 1. **Verify the command path:** ```bash - ls -la /path/to/mcp-server.js + ls -la /absolute/path/to/mcp-server.js ``` - The file must exist and be executable. + The file must exist and be executable. Replace `/absolute/path/to/mcp-server.js` with your actual MCP server path. 2. **Verify Node.js is installed:** ```bash @@ -366,9 +370,9 @@ Agents don't need special setup to discover tools. Here's the flow: 3. **Test the MCP server directly:** ```bash - node /path/to/mcp-server.js + node /absolute/path/to/mcp-server.js ``` - It should start without errors. If it crashes, there's a server-side issue. + It should start without errors. If it crashes, there's a server-side issue. Replace `/absolute/path/to/mcp-server.js` with your actual MCP server path. ### Authentication Errors @@ -414,13 +418,13 @@ Agents don't need special setup to discover tools. Here's the flow: "mcpServers": { "github": { "command": "node", - "args": ["/path/to/github-mcp.js"], + "args": ["/absolute/path/to/github-mcp.js"], "lazy": true } } } ``` - This starts the server only when its first tool is called. + This starts the server only when its first tool is called. Replace `/absolute/path/to/github-mcp.js` with your actual MCP server path. --- 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 82% rename from docs/features/model-selection.md rename to docs/src/content/docs/features/model-selection.md index 33bd81c70..3a26a51fa 100644 --- a/docs/features/model-selection.md +++ b/docs/src/content/docs/features/model-selection.md @@ -36,10 +36,10 @@ Model selection uses a layered system. First match wins: | Task Output | Model | Tier | |-------------|-------|------| -| Writing code (implementation, refactoring, tests, bug fixes) | `claude-sonnet-4.5` | Standard | -| Writing prompts or agent designs | `claude-sonnet-4.5` | Standard | +| Writing code (implementation, refactoring, tests, bug fixes) | `claude-sonnet-4.6` | Standard | +| Writing prompts or agent designs | `claude-sonnet-4.6` | Standard | | Non-code work (docs, planning, triage, changelogs) | `claude-haiku-4.5` | Fast | -| Visual/design work requiring image analysis | `claude-opus-4.5` | Premium | +| Visual/design work requiring image analysis | `claude-opus-4.6` | Premium | 4. **Default** — If nothing matched, `claude-haiku-4.5`. Cost wins when in doubt. @@ -47,30 +47,30 @@ Model selection uses a layered system. First match wins: | Role | Default Model | Why | |------|--------------|-----| -| Core Dev / Backend / Frontend | `claude-sonnet-4.5` | Writes code — quality first | -| Tester / QA | `claude-sonnet-4.5` | Writes test code | +| Core Dev / Backend / Frontend | `claude-sonnet-4.6` | Writes code — quality first | +| Tester / QA | `claude-sonnet-4.6` | Writes test code | | Lead / Architect | auto (per-task) | Mixed: code review vs. planning | | Prompt Engineer | auto (per-task) | Prompt design is like code | | DevRel / Writer | `claude-haiku-4.5` | Docs — not code | | Scribe / Logger | `claude-haiku-4.5` | Mechanical file ops | | Git / Release | `claude-haiku-4.5` | Changelogs, tags, version bumps | -| Designer / Visual | `claude-opus-4.5` | Vision capability required | +| Designer / Visual | `claude-opus-4.6` | Vision capability required | -## 16-Model Catalog +## 18-Model Catalog -Squad supports 16 models across three tiers: +Squad supports 18 models across three tiers: - **Premium:** claude-opus-4.6, claude-opus-4.6-fast, claude-opus-4.5 -- **Standard:** claude-sonnet-4.5, gpt-5.2-codex, claude-sonnet-4, gpt-5.2, gpt-5.1-codex, gpt-5.1, gpt-5, gemini-3-pro-preview -- **Fast/Cheap:** claude-haiku-4.5, gpt-5.1-codex-mini, gpt-4.1, gpt-5-mini, gpt-5.1-codex-mini +- **Standard:** claude-sonnet-4.6, gpt-5.4, gpt-5.3-codex, gpt-5.2-codex, claude-sonnet-4, gpt-5.2, gpt-5.1-codex, gpt-5.1, gpt-5, gemini-3-pro-preview +- **Fast/Cheap:** claude-haiku-4.5, gpt-5.1-codex-mini, gpt-4.1, gpt-5-mini ## Fallback Chains If a model is unavailable (plan restriction, rate limit, deprecation), Squad silently retries with the next in chain: ``` -Premium: claude-opus-4.6 → claude-opus-4.6-fast → claude-opus-4.5 → claude-sonnet-4.5 -Standard: claude-sonnet-4.5 → gpt-5.2-codex → claude-sonnet-4 → gpt-5.2 +Premium: claude-opus-4.6 → claude-opus-4.6-fast → claude-opus-4.5 → claude-sonnet-4.6 +Standard: claude-sonnet-4.6 → gpt-5.3-codex → gpt-5.4 → claude-sonnet-4 → gpt-5.2 Fast: claude-haiku-4.5 → gpt-5.1-codex-mini → gpt-4.1 → gpt-5-mini ``` diff --git a/docs/features/notifications.md b/docs/src/content/docs/features/notifications.md similarity index 82% rename from docs/features/notifications.md rename to docs/src/content/docs/features/notifications.md index 3f3392f4b..56ad6aa75 100644 --- a/docs/features/notifications.md +++ b/docs/src/content/docs/features/notifications.md @@ -1,4 +1,4 @@ -# Squad Pings You +# Squad pings you > ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. @@ -38,7 +38,7 @@ This means Squad works with any notification service. Pick your favorite messagi ## Quick Start: Teams (Simplest Path) -### Option A: Teams Incoming Webhook (No Auth Setup) +### Teams Incoming Webhook Teams webhooks are the fastest setup — just a URL. @@ -52,14 +52,23 @@ Teams webhooks are the fastest setup — just a URL. - Give it a name (e.g., "Squad Notifications") - Copy the webhook URL -3. **Configure Squad:** - - Create or edit `.vscode/mcp.json` in your workspace: +3. **Get the MCP server:** + + You need to create or download a Teams webhook MCP server. You have options: + + - **Community reference implementation:** [benleane83's teams-webhook-mcp.js](https://gist.github.com/benleane83/f37b5bc1ed3d00e320ba48886109b82a) — a working, production-ready implementation + - **Build your own:** Use the reference as a starting point and customize for your needs + - **Search MCP marketplace:** Look for Teams-compatible MCP servers at https://mcpmarket.com + +4. **Configure Squad:** + + Create or edit `.vscode/mcp.json` in your workspace: ```json { "mcpServers": { "notifications": { "command": "node", - "args": ["path/to/teams-webhook-mcp.js"], + "args": ["/absolute/path/to/teams-webhook-mcp.js"], "env": { "TEAMS_WEBHOOK_URL": "https://outlook.webhook.office.com/webhookb2/..." } @@ -67,48 +76,13 @@ Teams webhooks are the fastest setup — just a URL. } } ``` + + Replace `/absolute/path/to/teams-webhook-mcp.js` with the actual path to your downloaded or created MCP server script. -4. **Use it:** +5. **Use it:** - Start a Squad session with `copilot squad` - When an agent needs input, your Teams channel lights up -### Option B: Microsoft's Official Teams MCP Server (Full Auth) - -For integration with your Azure tenant and full Teams API access: - -1. **Register an Azure AD app:** - - Go to https://portal.azure.com → "Azure Active Directory" → "App registrations" - - New registration: name it "Squad Notifications" - - Copy the **Application (client) ID** - -2. **Set up credentials:** - - "Certificates & secrets" → "New client secret" - - Copy the secret value - -3. **Grant permissions:** - - "API permissions" → "Add a permission" → "Microsoft Graph" - - Add `Chat.Send`, `ChannelMessage.Send` - - Grant admin consent - -4. **Configure Squad:** - - Install Microsoft's Teams MCP server: https://github.com/microsoft/IF-MCP-Server-for-Microsoft-Teams - - Configure in `.vscode/mcp.json`: - ```json - { - "mcpServers": { - "teams": { - "command": "node", - "args": ["path/to/teams-mcp.js"], - "env": { - "AZURE_CLIENT_ID": "your-client-id", - "AZURE_CLIENT_SECRET": "your-secret", - "AZURE_TENANT_ID": "your-tenant-id" - } - } - } - } - ``` - --- ## Quick Start: iMessage (Mac Only) @@ -121,7 +95,7 @@ iMessage is built into macOS. If you're on a Mac, this is the fastest personal s - System allows Copilot to control Messages (grant permission when prompted) 2. **Install the iMessage MCP server:** - - Get it from https://mcpmarket.com/server/imessage + - Search https://mcpmarket.com for "imessage" or compatible MCP servers - Follow its setup steps 3. **Configure Squad:** @@ -131,7 +105,7 @@ iMessage is built into macOS. If you're on a Mac, this is the fastest personal s "mcpServers": { "imessage": { "command": "node", - "args": ["path/to/imessage-mcp.js"], + "args": ["/absolute/path/to/imessage-mcp.js"], "env": { "IMESSAGE_TARGET": "your-phone-number-or-email" } @@ -139,6 +113,8 @@ iMessage is built into macOS. If you're on a Mac, this is the fastest personal s } } ``` + + Replace `/absolute/path/to/imessage-mcp.js` with the actual path to your downloaded MCP server script. 4. **Test:** - Start a Squad session @@ -212,7 +188,7 @@ For any HTTP endpoint (custom service, Zapier, IFTTT, etc.): "mcpServers": { "notifications": { "command": "node", - "args": ["path/to/webhook-mcp.js"], + "args": ["/absolute/path/to/webhook-mcp.js"], "env": { "WEBHOOK_URL": "https://your-service.com/notify" } @@ -220,6 +196,8 @@ For any HTTP endpoint (custom service, Zapier, IFTTT, etc.): } } ``` + + Replace `/absolute/path/to/webhook-mcp.js` with the actual path to your MCP server script. 3. **Your endpoint receives POST:** ```json @@ -402,7 +380,7 @@ Below are complete, copy-pasteable `.copilot/mcp-config.json` examples for each "mcpServers": { "notifications": { "command": "node", - "args": ["path/to/teams-webhook-mcp.js"], + "args": ["/absolute/path/to/teams-webhook-mcp.js"], "env": { "TEAMS_WEBHOOK_URL": "https://outlook.webhook.office.com/webhookb2/YOUR_WEBHOOK_URL_HERE" } @@ -411,7 +389,10 @@ Below are complete, copy-pasteable `.copilot/mcp-config.json` examples for each } ``` -**Setup:** Get your webhook URL from Teams channel settings (right-click channel → Manage → Connectors → Incoming Webhook). +**Setup:** +1. Get your webhook URL from Teams channel settings (right-click channel → Manage → Connectors → Incoming Webhook) +2. Download a Teams webhook MCP server (see [community reference implementation](https://gist.github.com/benleane83/f37b5bc1ed3d00e320ba48886109b82a)) +3. Replace `/absolute/path/to/teams-webhook-mcp.js` with the actual path to your MCP server script --- @@ -422,7 +403,7 @@ Below are complete, copy-pasteable `.copilot/mcp-config.json` examples for each "mcpServers": { "notifications": { "command": "node", - "args": ["path/to/imessage-mcp.js"], + "args": ["/absolute/path/to/imessage-mcp.js"], "env": { "IMESSAGE_TARGET": "+1234567890" } @@ -431,7 +412,10 @@ Below are complete, copy-pasteable `.copilot/mcp-config.json` examples for each } ``` -Replace `+1234567890` with your phone number or email address registered in iCloud. +**Setup:** +1. Download an iMessage MCP server from https://mcpmarket.com +2. Replace `/absolute/path/to/imessage-mcp.js` with the actual path to your MCP server script +3. Replace `+1234567890` with your phone number or email address registered in iCloud --- @@ -442,7 +426,7 @@ Replace `+1234567890` with your phone number or email address registered in iClo "mcpServers": { "notifications": { "command": "node", - "args": ["path/to/discord-webhook-mcp.js"], + "args": ["/absolute/path/to/discord-webhook-mcp.js"], "env": { "DISCORD_WEBHOOK_URL": "https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN" } @@ -451,7 +435,10 @@ Replace `+1234567890` with your phone number or email address registered in iClo } ``` -**Setup:** In Discord, right-click channel → Edit Channel → Integrations → Webhooks → New Webhook → copy the URL. +**Setup:** +1. In Discord, right-click channel → Edit Channel → Integrations → Webhooks → New Webhook → copy the URL +2. Download or create a Discord webhook MCP server (see mcp-notifications package or build your own) +3. Replace `/absolute/path/to/discord-webhook-mcp.js` with the actual path to your MCP server script --- @@ -462,7 +449,7 @@ Replace `+1234567890` with your phone number or email address registered in iClo "mcpServers": { "notifications": { "command": "node", - "args": ["path/to/webhook-mcp.js"], + "args": ["/absolute/path/to/webhook-mcp.js"], "env": { "WEBHOOK_URL": "https://your-service.com/notify", "WEBHOOK_AUTH_HEADER": "Authorization: Bearer YOUR_API_KEY", @@ -473,7 +460,10 @@ Replace `+1234567890` with your phone number or email address registered in iClo } ``` -Your endpoint receives POST requests with agent name, message, and context. +**Setup:** +1. Create or download a generic webhook MCP server +2. Replace `/absolute/path/to/webhook-mcp.js` with the actual path to your MCP server script +3. Your endpoint receives POST requests with agent name, message, and context --- 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 74% rename from docs/features/reviewer-protocol.md rename to docs/src/content/docs/features/reviewer-protocol.md index 44fa21324..fa69b5e6b 100644 --- a/docs/features/reviewer-protocol.md +++ b/docs/src/content/docs/features/reviewer-protocol.md @@ -19,10 +19,6 @@ When a reviewer (Lead, Tester) rejects work, the original agent is locked out fr ## How It Works -When a reviewer (Lead, Tester) rejects an agent's work, the agent is **locked out** from self-revising. This prevents endless fix-retry loops and forces human oversight or escalation. The protocol ensures rejected work doesn't slip through without proper review. - -## How It Works - 1. **Agent submits work** — Creates draft PR, requests review from Lead or Tester. 2. **Reviewer evaluates** — Checks code quality, test coverage, adherence to directives. 3. **Reviewer decision:** @@ -133,6 +129,46 @@ Lockouts are recorded in `.squad/orchestration-log/`: [2024-01-15 16:20:11] UNLOCK: Fenster unlocked (issue #42 resolved) ``` +## Trust Levels for PR Management + +This section covers the spectrum of human oversight for Squad-created PRs: + +### 1. Full Review (Default) + +Every PR requires human approval before merge. This is the default and recommended for team repos, shared codebases, and anything with external collaborators. + +**When to use:** Team repositories, public packages, shared codebases where multiple people depend on stability. + +**Risk:** Low — human gate on every change. + +### 2. Selective Review + +Squad creates and reviews PRs, but the human only reviews PRs that touch specific paths or domains they care about. Everything else merges after agent review. + +**When to use:** Personal projects with established patterns where you trust Squad's judgment on routine changes (dependency updates, test fixes, doc improvements). + +**Risk:** Medium — some changes skip human eyes. + +### 3. Self-Managing (Personal Repos Only) + +Squad creates, reviews, approves, and merges its own PRs. The human only jumps in when an issue is explicitly flagged for review. + +**When to use:** Solo personal projects where you're the sole maintainer and experimentation speed matters more than pre-merge safety. + +**Risk:** Higher — but fast; review PRs retroactively. + +### Decision Matrix + +| Trust Level | When | Risk | +|-------------|------|------| +| Full review | Team repos, shared codebases, public packages | Low — human gate on every change | +| Selective review | Personal projects with established patterns | Medium — some changes skip human eyes | +| Self-managing | Solo personal projects, experimentation | Higher — but fast; review PRs retroactively | + +**Important:** Self-managing mode doesn't mean unmonitored. Use Ralph's work monitoring, Teams notifications, and periodic code review to stay informed. The difference is that you review *after* merge rather than *before*. + +--- + ## Sample Prompts ``` 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 88% rename from docs/features/skills.md rename to docs/src/content/docs/features/skills.md index 1ed26eb4b..55ca1923b 100644 --- a/docs/features/skills.md +++ b/docs/src/content/docs/features/skills.md @@ -40,6 +40,10 @@ Each skill is a directory containing a `SKILL.md` file. Skills are **team-wide k Bundled when you initialize Squad. Prefixed with `squad-` (e.g., `squad-conventions`). These encode baseline patterns for working with Squad. +### Session Recovery + +The `session-recovery` skill teaches agents to find and resume interrupted Copilot CLI sessions. When a session is interrupted (terminal crash, network drop, machine restart), in-progress work may be left incomplete. This skill uses `session_store` SQL queries to detect abandoned sessions, inspect checkpoint progress, and resume work. See [`.squad/skills/session-recovery/SKILL.md`](https://github.com/bradygaster/squad/blob/dev/.squad/skills/session-recovery/SKILL.md) for query patterns and examples. + ### Earned skills Written by agents from real work on your project. When an agent discovers a reusable pattern — a deployment strategy, a testing technique, an API integration approach — it writes a skill file. 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 91% rename from docs/features/team-setup.md rename to docs/src/content/docs/features/team-setup.md index f4e4a8e6e..eb1ec7fe3 100644 --- a/docs/features/team-setup.md +++ b/docs/src/content/docs/features/team-setup.md @@ -26,6 +26,10 @@ Squad analyzes your project and proposes a team roster with 3-7 members tailored When you first run Squad in a repository, it doesn't impose a team — it proposes one. The init flow analyzes your project, suggests roles and members, waits for your confirmation, then creates the `.squad/` directory structure and installs the crew. +### Character Casting + +By default, Squad uses the **CastingEngine** to assign agent names from fictional universes (The Usual Suspects, Ocean's Eleven, etc.). The LLM proposes roles and team composition; the engine allocates curated character names, personalities, and backstories from the selected universe. Use `squad init --roles` to opt into the base role catalog (Lead, Backend, Frontend, Tester) instead of universe casting. + ## How Init Works 1. **Discovery** — Squad scans your repository: language distribution, file structure, test frameworks, dependencies, existing workflows. diff --git a/docs/src/content/docs/features/upstream-inheritance.md b/docs/src/content/docs/features/upstream-inheritance.md new file mode 100644 index 000000000..d6288a92e --- /dev/null +++ b/docs/src/content/docs/features/upstream-inheritance.md @@ -0,0 +1,410 @@ +# Upstream Inheritance + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +Upstream inheritance lets you declare external Squad sources (from repositories, local directories, or exports) and automatically inherit their context at session start. Share practices across teams, organizations, and projects without duplicating configuration. + +## How it works + +At session start, the coordinator reads all declared upstreams from `upstream.json` and makes their context available to every agent: + +- **Skills** — `.squad/skills/*/SKILL.md` +- **Decisions** — `.squad/decisions.md` +- **Wisdom** — `.squad/identity/wisdom.md` +- **Casting policy** — `.squad/casting/policy.json` +- **Routing** — `.squad/routing.md` + +**Resolution order:** Later entries override earlier ones. Layer upstreams from org → team → repo, with each level adding or overriding as needed. + +**Source types:** + +| Type | Example | Use case | +|------|---------|----------| +| **local** | `../org-practices/.squad/` | Sibling repo, shared drive, monorepo package | +| **git** | `https://github.com/acme/platform-squad.git` | Public/private team repo (with credentials) | +| **export** | `./exports/squad-export.json` | Snapshot for offline use or version pinning | + +## Quick start + +**Local upstream:** + +```bash +squad upstream add ../org-practices/.squad +squad upstream list +# org-practices → local: /path/to/org-practices/.squad (never synced) +``` + +**Git upstream:** + +```bash +squad upstream add https://github.com/acme/platform-squad.git --name platform --ref main +squad upstream sync platform +``` + +**Export snapshot:** + +```bash +squad export-config --output ./exports/snapshot.json +squad upstream add ./exports/snapshot.json --name snapshot +``` + +## Troubleshooting + +### Git clone or sync fails + +Ensure the URL is correct and you have access. For private repos, use SSH (`git@github.com:owner/repo.git`) with your SSH key in ssh-agent, or use a GitHub PAT with `https://[PAT]@github.com/owner/repo.git`. + +### Local upstream not found + +Verify the path exists: `ls ../shared/.squad`. Use absolute paths if relative paths fail. + +### Agents don't see inherited context + +```bash +# Verify upstreams are configured +squad upstream list + +# Sync and validate sources +squad upstream sync + +# Restart your session (resolution happens at session start) +``` + +For git upstreams, check `.squad/_upstream_repos/{name}` exists. + +### Cached clone out of date + +```bash +squad upstream sync +``` + +Then start a new session. + +### Conflicting upstreams + +Later entries in `upstream.json` override earlier ones. Check order with `squad upstream list`. Reorder with `remove` + `add` if needed. + +## CLI Reference + +### `squad upstream add ` + +Add a new upstream source. + +**Signature:** +``` +squad upstream add [--name ] [--ref ] +``` + +**Arguments:** +- `` — File path, git URL, or export JSON file. Squad auto-detects the type. + +**Options:** +- `--name ` — Display name (optional; defaults to repo/dir name) +- `--ref ` — Git branch/tag (only for git sources; defaults to `main`) + +**Examples:** + +Local directory: +```bash +squad upstream add ../shared-squad --name shared +``` + +Git repository: +```bash +squad upstream add https://github.com/acme/platform-squad.git --name platform --ref main +``` + +Export file: +```bash +squad upstream add ./exports/org-snapshot.json --name org-snapshot +``` + +**What happens:** +- Reads `upstream.json` from `.squad/` +- Detects source type (local, git, export) +- For git sources: auto-clones to `.squad/_upstream_repos/{name}` +- Adds entry to `.squad/upstream.json` +- For local/export: coordinator reads live at session start (no sync needed) + +### `squad upstream remove ` + +Remove an upstream by name. + +**Signature:** +``` +squad upstream remove +``` + +**Examples:** +```bash +squad upstream remove platform +``` + +**What happens:** +- Removes entry from `.squad/upstream.json` +- Deletes cached clone from `.squad/_upstream_repos/{name}` if it exists + +### `squad upstream list` + +Show all configured upstreams. + +**Signature:** +``` +squad upstream list +``` + +**Output example:** +``` +Configured upstreams: + + platform → git: https://github.com/acme/platform-squad.git (ref: main) (synced 2026-02-22) + shared → local: /home/alice/shared-squad (never synced) + snapshot → export: ./exports/org-snapshot.json (synced 2026-02-22) +``` + +### `squad upstream sync [name]` + +Update cached clones for git upstreams, or validate paths for local/export upstreams. + +**Signature:** +``` +squad upstream sync [name] +``` + +**Examples:** + +Sync all: +```bash +squad upstream sync +``` + +Sync one: +```bash +squad upstream sync platform +``` + +**What happens:** +- For **git** sources: `git pull --ff-only` on the cached clone, or re-clones if needed +- For **local** sources: validates that the path exists +- For **export** sources: validates that the file exists +- Updates `last_synced` timestamp in `upstream.json` + +## SDK API Reference + +The upstream module provides resolver functions for programmatic use. + +### Types + +#### `UpstreamType` + +```typescript +type UpstreamType = 'local' | 'git' | 'export'; +``` + +#### `UpstreamSource` + +A declared upstream from `upstream.json`: + +```typescript +interface UpstreamSource { + name: string; // Display name (e.g., "platform") + type: UpstreamType; // How to access it + source: string; // Path, URL, or export file location + ref?: string; // Git ref (only for type: "git") + added_at: string; // ISO timestamp + last_synced: string | null; // Last successful sync +} +``` + +#### `UpstreamConfig` + +The `upstream.json` file format: + +```typescript +interface UpstreamConfig { + upstreams: UpstreamSource[]; +} +``` + +#### `ResolvedUpstream` + +Resolved content from a single upstream: + +```typescript +interface ResolvedUpstream { + name: string; + type: UpstreamType; + skills: Array<{ name: string; content: string }>; + decisions: string | null; + wisdom: string | null; + castingPolicy: Record | null; + routing: string | null; +} +``` + +#### `UpstreamResolution` + +Result of resolving all upstreams: + +```typescript +interface UpstreamResolution { + upstreams: ResolvedUpstream[]; +} +``` + +### Functions + +#### `readUpstreamConfig(squadDir: string): UpstreamConfig | null` + +Read and parse `upstream.json` from a squad directory. + +**Returns:** `null` if file doesn't exist or is invalid. + +**Example:** +```typescript +import { readUpstreamConfig } from '@bradygaster/squad-sdk'; + +const config = readUpstreamConfig('.squad'); +if (config) { + console.log(`Found ${config.upstreams.length} upstreams`); +} +``` + +#### `resolveUpstreams(squadDir: string): UpstreamResolution | null` + +Resolve all upstream sources declared in `upstream.json`. + +For each upstream: +- **local**: reads directly from the source's `.squad/` +- **git**: reads from `.squad/_upstream_repos/{name}/` (must be cloned first) +- **export**: reads from the JSON file + +**Returns:** `null` if no `upstream.json` exists. If a source can't be reached, that upstream is included with empty content (no error thrown). + +**Example:** +```typescript +import { resolveUpstreams } from '@bradygaster/squad-sdk'; + +const resolution = resolveUpstreams('.squad'); +if (resolution) { + for (const upstream of resolution.upstreams) { + console.log(`${upstream.name}: ${upstream.skills.length} skills`); + } +} +``` + +#### `buildInheritedContextBlock(resolution: UpstreamResolution | null): string` + +Build a text block summarizing inherited context (for agent prompts). + +**Returns:** Empty string if no resolution or upstreams. + +**Example output:** +``` +INHERITED CONTEXT: + platform: skills (3), decisions ✓, casting ✓ + shared: skills (5), routing ✓ + snapshot: (empty) +``` + +**Usage:** The coordinator includes this in agent spawn prompts to signal what context is available. + +#### `buildSessionDisplay(resolution: UpstreamResolution | null): string` + +Build a user-facing display for session start greeting. + +**Returns:** Empty string if no resolution or upstreams. + +**Example output:** +``` +📡 Inherited context: + platform (git) — 3 skills, decisions, casting + shared (local) — 5 skills, routing + ⚠️ snapshot (export) — source not reachable +``` + +**Usage:** Shown in the session greeting to confirm what upstreams are available. + +## Use cases + +### Shared practices across teams + +**Problem:** Multiple teams need consistent agent definitions, decisions, and casting policy without duplicating configuration. + +**Solution:** Create a central Squad repo (platform-squad) with shared context. Product teams add it as an upstream. + +```bash +# In platform-squad repo +.squad/ + decisions.md + casting/policy.json + skills/ + platform-engineer/SKILL.md + backend-engineer/SKILL.md + +# In product-a repo +squad upstream add https://github.com/acme/platform-squad.git --name platform --ref main +``` + +**Outcome:** Platform team updates practices once. All product teams inherit changes at next `squad upstream sync`. Product teams can layer their own skills or override decisions as needed. + +**Also works for:** +- Open-source frameworks with community plugins +- Consultancy methodology across client projects + +--- + +### Domain consistency across services + +**Problem:** Multiple microservices share a domain model (user, order, payment). You need a single source of truth for how agents work with that model. + +**Solution:** Create a shared-domain repo with domain-specific skills and decisions. Each service adds it as an upstream. + +```bash +# In shared-domain repo +.squad/ + skills/ + domain-modeler/SKILL.md + database-engineer/SKILL.md + decisions.md + routing.md + +# In user-service, order-service, payment-service repos +squad upstream add https://github.com/acme/shared-domain.git --name domain +``` + +**Outcome:** All agents across services understand the domain model. Domain conventions change once; each service pulls independently. Services stay decoupled with consistency. + +--- + +### Multi-team scaling patterns + +**Problem:** Post-acquisition, migration, or enterprise modernization requires coordinating practices across teams with different histories. + +**Solution:** Create a unified practices or playbook repo. All teams add it as an upstream. + +```bash +# In acme-unified-practices repo (post-acquisition example) +.squad/ + decisions.md # Merged decision framework + casting/policy.json # Unified roles + skills/ + acme-engineer/SKILL.md + acquired-engineer/SKILL.md + +# In both original and acquired product repos +squad upstream add https://github.com/acme/acme-unified-practices.git --name unified +``` + +**Outcome:** Teams work independently while culturally aligned. Agents understand both traditions. Gradual convergence without painful rewrites. + +**Also works for:** +- Monolith-to-microservices modernization (playbook defines architecture patterns) +- Multi-geo teams converging on shared standards + +## Next Steps + +- **Read more:** See `docs/guide/casting.md` for how inherited casting policy shapes agent behavior +- **Set up**: Run `squad upstream add ` to add your first upstream +- **Share:** Export your Squad config with `squad export-config` for others to inherit +- **Iterate:** Update your upstream and run `squad upstream sync` to pull changes across all consuming projects 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/choose-your-interface.md b/docs/src/content/docs/get-started/choose-your-interface.md new file mode 100644 index 000000000..006c49b5d --- /dev/null +++ b/docs/src/content/docs/get-started/choose-your-interface.md @@ -0,0 +1,174 @@ +# Choose your interface + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + + +Squad works across multiple interfaces. Pick the one that fits your workflow. + +--- + +## Try this: + +```bash +# Day-to-day work with your squad +copilot --agent squad + +# Setup and diagnostics +squad init +squad doctor +``` + +--- + +## What are the ways to use Squad? + +Squad runs in multiple modes and across multiple platforms: + +### GitHub Copilot CLI (`copilot` command) + +The conversational terminal interface. Powered by the GitHub Copilot CLI, this is the recommended way to work with Squad day-to-day. + +```bash +copilot --agent squad +``` + +Reads `.squad/` and uses `squad.agent.md` to coordinate your team. Full feature set — sub-agent spawning, per-spawn model selection, background execution, SQL tools, parallel fan-out. + +### VS Code (GitHub Copilot in the editor) + +Squad works identically in VS Code through GitHub Copilot. Same `.squad/` directory, same agents, same decisions. Full file access, parallel execution, MCP tool inheritance. See [Squad in VS Code](../features/vscode.md) for details. + +### Squad CLI (`squad` command) + +The Squad CLI provides setup, diagnostics, and automation commands. Not conversational — use this for installation, validation, and operational tasks. + +```bash +# Setup +squad init + +# Validation +squad doctor + +# Monitoring +squad watch + +# Observability +squad aspire +``` + +See [CLI Reference](../reference/cli.md) for all commands. + +### Interactive shell (`squad start` / `squad shell`) + +REPL mode for conversational interaction directly via the Squad CLI. Enter `squad` with no arguments to start a persistent shell session. See [Interactive Shell Guide](../guide/shell.md). + +This works, but **GitHub Copilot CLI is recommended** — richer agent experience, better tools, full MCP integration. + +### SDK (`@bradygaster/squad-sdk`) + +Programmatic access for building tools on top of Squad. Typed APIs, routing config, agent lifecycle hooks. + +```bash +npm install @bradygaster/squad-sdk +``` + +```typescript +import { resolveSquad, loadConfig, SquadCoordinator } from '@bradygaster/squad-sdk'; +``` + +See [SDK Reference](../reference/sdk.md) for the complete API. + +### Copilot Coding Agent (`@copilot`) + +Autonomous GitHub bot that picks up labeled issues and opens draft PRs. Works across your entire organization without human intervention. Issue gets labeled → agent picks it up → PR gets opened → human reviews. + +See [Copilot Coding Agent](../features/copilot-coding-agent.md) for setup. + +--- + +## Which should I use? + +| You want to... | Use | Why | +|----------------|-----|-----| +| **Work with your squad day-to-day** | **GitHub Copilot CLI** or **VS Code** | Conversational interface, full agent spawning, parallel execution. Most natural way to collaborate with your team. | +| **Set up Squad in a new repo** | **Squad CLI** (`squad init`) | One command initializes `.squad/` directory and all configuration. | +| **Check if Squad is working** | **Squad CLI** (`squad doctor`) | Validates directory structure, agents, configuration integrity. | +| **Monitor work 24/7** | **Squad CLI** (`squad watch`) | Persistent polling for new issues, auto-triage, agent assignment. | +| **View OpenTelemetry traces** | **Squad CLI** (`squad aspire`) | Launches Aspire dashboard for observability. | +| **Process issues autonomously** | **Copilot Coding Agent** | GitHub Actions workflow watches for labeled issues and dispatches `@copilot`. | +| **Build tools on top of Squad** | **SDK** | Typed APIs, configuration loading, agent lifecycle hooks. | + +--- + +## Feature availability matrix + +Not every feature works everywhere. Here's what's available where: + +| Feature | GitHub Copilot CLI | VS Code | Squad CLI | SDK | +|---------|:------------------:|:-------:|:---------:|:---:| +| Agent spawning | ✅ | ✅ | ✅ (via shell) | ✅ | +| Ralph / work monitoring | ✅ | ✅ | ✅ (`squad watch`) | ✅ | +| Per-spawn model selection | ✅ | ⚠️ (session model only) | ✅ | ✅ | +| Background execution | ✅ | ⚠️ (parallel sync) | ✅ | ✅ | +| SQL tool | ✅ | ❌ | ✅ | ✅ | +| Aspire dashboard | ❌ | ❌ | ✅ | ❌ | +| `squad doctor` diagnostics | ❌ | ❌ | ✅ | ✅ | +| Issue assignment to `@copilot` | ❌ | ❌ | ✅ (setup) | ❌ | + +**Legend:** +- ✅ Fully supported +- ⚠️ Limited or constrained +- ❌ Not available + +For a detailed breakdown of VS Code constraints and CLI parity, see [Client Compatibility Matrix](../scenarios/client-compatibility.md). + +--- + +## Common workflows + +### "I use GitHub Copilot CLI for everything" + +```bash +# Terminal 1: Work with Squad +copilot --agent squad + +# Let Squad call `squad` commands when needed (doctor, watch, aspire) +``` + +This is the recommended workflow. The CLI automatically invokes Squad CLI commands when needed. + +### "I run squad watch in one terminal and use GitHub Copilot CLI in another" + +```bash +# Terminal 1: Monitoring (persistent) +squad watch --interval 10 + +# Terminal 2: Work with Squad +copilot --agent squad +``` + +Keep Ralph monitoring issues in the background while you work conversationally. + +### "I use VS Code with Copilot for coding and Squad CLI for setup" + +```bash +# One-time setup +squad init +squad doctor + +# Open VS Code, select Squad from agent picker +# Same .squad/ directory, same team +``` + +Initialize with CLI, work in VS Code. + +--- + +## See also + +- [Installation](installation.md) — Install Squad CLI, SDK, or use in VS Code +- [First Session](first-session.md) — Get started with your first Squad conversation +- [Client Compatibility Matrix](../scenarios/client-compatibility.md) — Full feature comparison across platforms +- [CLI Reference](../reference/cli.md) — All Squad CLI commands +- [Squad in VS Code](../features/vscode.md) — VS Code-specific guidance +- [SDK Reference](../reference/sdk.md) — Programmatic API 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..6e7600b92 --- /dev/null +++ b/docs/src/content/docs/get-started/five-minute-start.md @@ -0,0 +1,96 @@ +# 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 + .github/workflows/ — 5 GitHub workflows (heartbeat, triage, CI, etc.) + .squad/templates/ — 11 template files + +Open GitHub Copilot and select Squad from the agent list. +``` + +> **Don't forget:** Commit the generated files — workflows won't run until they're on your default branch. +> +> ```bash +> git add .github/ .squad/ +> git commit -m "chore: initialize squad team" +> git push +> ``` + +--- + +## 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/src/content/docs/get-started/installation.md b/docs/src/content/docs/get-started/installation.md new file mode 100644 index 000000000..03f9d818f --- /dev/null +++ b/docs/src/content/docs/get-started/installation.md @@ -0,0 +1,272 @@ +# Installation + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + + +Three ways to get Squad running. Pick the one that fits. + +--- + +## Try this: + +```bash +npm install -g @bradygaster/squad-cli +squad +``` + +That's it. You're in. + +--- + +## 1. CLI (Recommended) + +The CLI is the fastest way to use Squad from any terminal. + +### Global install + +```bash +npm install -g @bradygaster/squad-cli +``` + +Now use it anywhere: + +```bash +squad init +squad status +squad watch +``` + +### One-off with npx + +No install needed — run the latest version directly: + +```bash +npx @bradygaster/squad-cli init +npx @bradygaster/squad-cli status +``` + +### Verify + +```bash +squad --version +``` + +### Update + +```bash +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. + +> **Tip:** Initialize your team with the CLI (`squad`), then open the project in VS Code to keep working with the same squad. + +--- + +## 3. SDK + +Building your own tooling on top of Squad? Install the SDK as a project dependency: + +```bash +npm install @bradygaster/squad-sdk +``` + +Then import what you need: + +```typescript +import { defineConfig, loadConfig, resolveSquad } from '@bradygaster/squad-sdk'; +``` + +The SDK gives you typed configuration, routing, model selection, and the full agent lifecycle API. See the [SDK Reference](../reference/sdk.md) for details. + +--- + +## Not sure which interface to use? + +See [Choose your interface](choose-your-interface.md) for a complete breakdown of GitHub Copilot CLI, VS Code, Squad CLI, SDK, and the Copilot Coding Agent. + +--- + +### Personal squad (cross-project) + +Want the same agents across all your projects? + +```bash +squad init --global +``` + +This creates your personal squad directory — a personal team root that any project can inherit from. See [Upstream Inheritance](../features/upstream-inheritance.md) for details. + +**Personal squad location by platform:** + +| Platform | Path | +|----------|------| +| Linux | `~/.config/squad/` | +| macOS | `~/Library/Application Support/squad/` | +| Windows | `%APPDATA%\squad\` | + +### SDK mode + +Generate a typed `squad.config.ts` with `useRole()` calls instead of markdown-only setup: + +```bash +squad init --sdk +``` + +Combine with `--roles` to include the base role catalog (Lead, Backend, Frontend, Tester, etc.) in the generated config. Without `--roles`, init uses fictional universe casting by default. + +```bash +squad init --sdk --roles +``` + +--- + +## First-Time Setup + +After installing, initialize Squad in your project: + +```bash +cd your-project +squad init +``` + +This creates: + +``` +.github/agents/squad.agent.md — coordinator agent +.github/workflows/ — GitHub workflows (see below) +.squad/ — team state directory +.squad/templates/ — template files for casting, routing, ceremonies +``` + +### What `squad init` installs + +Beyond the coordinator agent and team state, `squad init` creates GitHub workflows in `.github/workflows/`: + +| Workflow | Purpose | +|----------|---------| +| `squad-heartbeat.yml` | Ralph's triage loop — auto-assigns issues to squad members based on routing rules | +| `squad-triage.yml` | Issue triage automation | +| `squad-issue-assign.yml` | Auto-assign issues to squad members | +| `squad-label-enforce.yml` | Label state machine enforcement | +| `squad-ci.yml` | Build & test integration | + +> **Important:** These workflows are created but may need a separate commit. If `squad init` is run inside a Copilot session, the generated workflow files are staged but not committed. Commit them explicitly: +> +> ```bash +> git add .github/workflows/ .github/agents/ .squad/ +> git commit -m "chore: initialize squad team" +> ``` + +### Enabling the heartbeat schedule + +The heartbeat workflow runs Ralph's triage automatically. By default, the cron schedule is **disabled** — it only triggers on issue/PR events and manual dispatch. To enable periodic triage: + +1. Open `.github/workflows/squad-heartbeat.yml` +2. Uncomment the `schedule` block: + +```yaml +on: + schedule: + # Every 30 minutes — adjust to your team's pace + - cron: '*/30 * * * *' +``` + +**Common schedule examples:** + +| Schedule | Cron Expression | +|----------|----------------| +| Every 30 minutes | `*/30 * * * *` | +| Every hour | `0 * * * *` | +| Every 4 hours during business hours | `0 9-17/4 * * 1-5` | +| Once daily at 9 AM UTC | `0 9 * * *` | + +### Adding Squad to an existing project + +Already have a running project? `squad init` works the same way — it won't overwrite your existing files: + +```bash +cd my-existing-project +squad init +``` + +**Tip:** After initializing, give Squad context about your project in your first session: + +``` +> This is a React + Node.js task management app. We use PostgreSQL, +> deploy to AWS, and follow trunk-based development. The main entry +> points are src/server/index.ts and src/client/App.tsx. +``` + +Squad uses this to form a team matched to your stack and write accurate routing rules. See [Adding Squad to an Existing Repo](../scenarios/existing-repo.md) for a detailed walkthrough. + +### Configuration (optional) + +For typed configuration, create a `squad.config.ts` at your project root: + +```typescript +import { defineConfig } from '@bradygaster/squad-sdk'; + +export default defineConfig({ + team: { + name: 'my-squad', + root: '.squad', + description: 'My project team', + }, +}); +``` + +`defineConfig()` gives you full autocomplete and validation. But you don't need it to get started — Squad works out of the box with sensible defaults. + +--- + +## Troubleshooting + +### `squad: command not found` + +Your npm global bin isn't in your PATH. Fix: + +```bash +# Check if installed +npm list -g @bradygaster/squad-cli + +# If installed but not found, check PATH: +echo $PATH | grep npm # macOS/Linux +echo %PATH% | findstr npm # Windows +``` + +### `Cannot find .squad/ directory` + +Run `squad init` in your project root, or `squad init --global` for a personal squad. + +### Version mismatch between CLI and SDK + +Update both: + +```bash +npm install -g @bradygaster/squad-cli@latest +npm install @bradygaster/squad-sdk@latest +``` + +--- + +## Ready? → [Your First Session](first-session.md) diff --git a/docs/get-started/migration.md b/docs/src/content/docs/get-started/migration.md similarity index 85% rename from docs/get-started/migration.md rename to docs/src/content/docs/get-started/migration.md index 11eecb5c3..ea57135d9 100644 --- a/docs/get-started/migration.md +++ b/docs/src/content/docs/get-started/migration.md @@ -16,7 +16,7 @@ - [Scenario 9: Using Squad SDK Programmatically](#scenario-9-using-squad-sdk-programmatically) - [Troubleshooting](#troubleshooting) - [Rolling Back](#rolling-back) -- [What's New in v0.8.18](#whats-new-in-v0818) +- [What's New in v0.8.18+](#whats-new-in-v0818) --- @@ -27,7 +27,7 @@ | `npx github:bradygaster/squad` | `npx @bradygaster/squad-cli` | | `@bradygaster/create-squad` | `@bradygaster/squad-cli` | | `.ai-team/` directory | `.squad/` directory | -| v0.5.4 (beta) | v0.8.18 | +| v0.5.4 (beta) | v0.8.x (latest) | --- @@ -37,7 +37,7 @@ Never used Squad before? Start here. ### Prerequisites -- Node.js 18 or later +- Node.js 20 or later - npm 9 or later - A GitHub account with [GitHub Copilot](https://github.com/features/copilot) enabled - `gh` CLI authenticated (`gh auth status` should show you logged in) @@ -80,7 +80,7 @@ This is the biggest jump. The codebase was rewritten in TypeScript, the `.squad/ ### What Changed - **TypeScript rewrite:** Entire codebase ported from JavaScript to TypeScript (strict mode). -- **`.squad/` directory format:** v0.5.4 format is incompatible with v0.8.18. You must reinitialize. +- **`.squad/` directory format:** v0.5.4 format is incompatible with v0.8.x. You must reinitialize. - **Command structure:** Some commands were reorganized or renamed. - **SDK API:** The public API changed significantly if you were using Squad programmatically. - **Distribution:** npm-only. The `npx github:` install path is gone. @@ -99,10 +99,21 @@ This is the biggest jump. The codebase was rewritten in TypeScript, the `.squad/ npm uninstall -g @bradygaster/create-squad ``` -3. **Install v0.8.18:** +3. **Install the latest version:** + **Global (recommended):** ```bash - npm install -g @bradygaster/squad-cli@0.8.18 + npm install -g @bradygaster/squad-cli@latest + ``` + + **Local (project dependency):** + ```bash + npm install --save-dev @bradygaster/squad-cli@latest + ``` + + **npx (no install):** + ```bash + npx @bradygaster/squad-cli@latest ``` 4. **Remove the old `.squad/` directory:** @@ -144,7 +155,7 @@ This is the biggest jump. The codebase was rewritten in TypeScript, the `.squad/ ### Key Format Changes -| v0.5.4 | v0.8.18 | +| v0.5.4 | v0.8.x (latest) | |--------|---------| | `.squad/config.json` | `.squad/team.md` (Markdown with YAML front matter) | | JSON decision log | `.squad/decisions.md` (append-only Markdown) | @@ -156,17 +167,26 @@ This is the biggest jump. The codebase was rewritten in TypeScript, the `.squad/ If you're already on any v0.8.x release, this is a simple update. +**Global:** ```bash npm install -g @bradygaster/squad-cli@latest ``` +**Local:** +```bash +npm install --save-dev @bradygaster/squad-cli@latest +``` + +**npx:** +If you use `npx`, no update needed — it always pulls the latest version. + Verify the version: ```bash squad --version ``` -Expected output: `0.8.18` (or `0.8.18-preview.N`). +Expected output: the latest `0.8.x` version (e.g., `0.8.25`). Your `.squad/` directory is compatible — no reinitialization needed. @@ -290,15 +310,15 @@ If you run Squad in GitHub Actions or another CI/CD system, update your workflow run: npx github:bradygaster/squad ``` -### After (v0.8.18) +### After (v0.8.x) ```yaml - uses: actions/setup-node@v4 with: - node-version: '18' + node-version: '20' - name: Install Squad - run: npm install -g @bradygaster/squad-cli@0.8.18 + run: npm install -g @bradygaster/squad-cli@latest - name: Run Squad run: squad doctor && squad status @@ -309,9 +329,9 @@ If you run Squad in GitHub Actions or another CI/CD system, update your workflow ### Key CI/CD Notes - Set `GITHUB_TOKEN` as an environment variable. Squad requires it for GitHub Copilot operations. -- Pin to a specific version (`@0.8.18`) in CI to avoid surprise upgrades. -- If you use `npx`, use `npx @bradygaster/squad-cli@0.8.18` with a pinned version. -- Node.js 18+ is required. Update your workflow's `setup-node` action if needed. +- Pin to a specific version (e.g., `@0.8.25`) in CI to avoid surprise upgrades, or use `@latest` to stay current. +- If you use `npx`, use `npx @bradygaster/squad-cli@latest` (or pin a specific version). +- Node.js 20+ is required. Update your workflow's `setup-node` action if needed. --- @@ -342,7 +362,7 @@ import { Squad } from '@bradygaster/squad-sdk'; ### API Notes - The SDK is now fully typed (TypeScript strict mode). -- Some methods were renamed or reorganized. Check the [SDK documentation](sdk/) for the current API surface. +- Some methods were renamed or reorganized. Check the [SDK documentation](../reference/sdk.md) for the current API surface. - If you were relying on internal/undocumented APIs, those have changed. Stick to the documented public API. --- @@ -428,13 +448,13 @@ Clear the npx cache and retry: ```bash npx clear-npx-cache -npx @bradygaster/squad-cli@0.8.18 +npx @bradygaster/squad-cli@latest ``` Or install globally to bypass npx caching entirely: ```bash -npm install -g @bradygaster/squad-cli@0.8.18 +npm install -g @bradygaster/squad-cli@latest ``` ### Wrong version installed @@ -449,7 +469,7 @@ If it shows an old version: ```bash npm uninstall -g @bradygaster/squad-cli -npm install -g @bradygaster/squad-cli@0.8.18 +npm install -g @bradygaster/squad-cli@latest ``` ### Team roster gone after upgrade @@ -473,34 +493,34 @@ Common causes: - Missing `.squad/` directory — run `squad init`. - Missing `GITHUB_TOKEN` — see [GITHUB_TOKEN issues](#github_token-issues) above. -- Node.js too old — upgrade to Node.js 18+. +- Node.js too old — upgrade to Node.js 20+. - Corrupted `.squad/` files — back up, remove, and reinitialize. ### Node.js version too old -Squad requires Node.js 18 or later. Check your version: +Squad requires Node.js 20 or later. Check your version: ```bash node --version ``` -If below 18, upgrade via [nodejs.org](https://nodejs.org/) or your preferred version manager: +If below 20, upgrade via [nodejs.org](https://nodejs.org/) or your preferred version manager: ```bash # nvm -nvm install 18 -nvm use 18 +nvm install 20 +nvm use 20 # fnm -fnm install 18 -fnm use 18 +fnm install 20 +fnm use 20 ``` --- ## Rolling Back -If you need to downgrade from v0.8.18: +If you need to downgrade to a previous v0.8.x release: ```bash npm install -g @bradygaster/squad-cli@0.8.17 @@ -510,19 +530,23 @@ npm install -g @bradygaster/squad-cli@0.8.17 - **The GitHub-native distribution (`npx github:bradygaster/squad`) is permanently removed.** You cannot roll back to that install method. - **`.squad/` directory format changed between v0.5.4 and v0.8.x.** If you roll back to v0.5.4, your current `.squad/` directory will not be compatible. Keep backups. -- Rolling back within the v0.8.x line (e.g., 0.8.18 to 0.8.17) should be safe — the `.squad/` format is stable across v0.8.x releases. +- Rolling back within the v0.8.x line (e.g., 0.8.25 to 0.8.24) should be safe — the `.squad/` format is stable across v0.8.x releases. --- -## What's New in v0.8.18 +## What's New in v0.8.18+ + +Key improvements since the migration from v0.5.4 beta: - **Remote Squad Mode:** `squad link`, `squad init --mode remote`, and dual-root path resolution for team identity directories. - **`squad doctor`:** 9-check setup validation with clear pass/fail output. - **npm-only distribution:** Simpler install, semantic versioning, stable and insider channels. - **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`). +- **Semver fix:** Version format now follows the semver spec (`0.8.x-preview.N`). +- **Node 22+ compatibility:** ESM import fixes for vscode-jsonrpc (v0.8.23+). +- **Casting system:** Universe-based agent naming with persistent registries (v0.8.25+). -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 56% rename from docs/guide.md rename to docs/src/content/docs/guide.md index c13fdb245..246809f77 100644 --- a/docs/guide.md +++ b/docs/src/content/docs/guide.md @@ -8,16 +8,42 @@ It is not a chatbot wearing hats. Each team member is spawned as a real sub-agen --- +## Which CLI should I use? + +**Use GitHub Copilot CLI for day-to-day work.** It's the recommended interface for interacting with your Squad — full agent spawning, model selection, and conversational access to all features. + +**Use Squad CLI for setup and operations:** +- Initial setup: `squad init` +- Diagnostics: `squad doctor` +- Continuous triage: `squad triage --interval 10` +- Aspire dashboard: `squad aspire` +- Export/import: `squad export` and `squad import` + +**Common workflow:** +```bash +# Terminal 1: Run continuous triage (Squad CLI) +squad triage --interval 10 + +# Terminal 2: Work with your team (GitHub Copilot CLI) +gh copilot +> @squad what issues are ready to work? +``` + +Both CLIs read and write the same `.squad/` directory, so state stays synchronized. For more details, see [FAQ: Which CLI should I use?](guide/faq.md#which-cli-should-i-use) and [Client Compatibility Matrix](scenarios/client-compatibility.md). + +--- + ## Supported Platforms -Squad is designed for **GitHub Copilot CLI** and ships with full support. **VS Code is now fully supported with zero code changes** — agents work identically on both platforms. +Squad works across multiple interfaces — GitHub Copilot CLI, VS Code, Squad CLI, SDK, and the Copilot Coding Agent. Pick the one that fits your workflow: -**Current state:** -- ✅ **GitHub Copilot CLI** — fully supported. This is the primary platform. Uses the stable `task` tool for sub-agent spawning, per-spawn model selection, and background mode. -- ✅ **VS Code Copilot** — fully supported (v0.4.0+). VS Code uses `runSubagent` for parallel execution and supports full `.ai-team/` read/write. See [Client Compatibility Matrix](scenarios/client-compatibility.md) for details. -- ❌ **Other platforms** — JetBrains IDEs and other runtimes are untested. GitHub.com web-based Copilot is untested. +- **GitHub Copilot CLI** — Day-to-day conversational work with your squad (recommended) +- **VS Code** — Same experience, editor-integrated +- **Squad CLI** — Setup, diagnostics, monitoring (`squad init`, `squad doctor`, `squad watch`) +- **SDK** — Build tools on top of Squad +- **Copilot Coding Agent** — Autonomous issue processing via `@copilot` -For a detailed feature comparison across platforms (model selection, background execution, file access, etc.), see [Client Compatibility Matrix](scenarios/client-compatibility.md). +Not sure which to use? See [Choose your interface](get-started/choose-your-interface.md) for a complete comparison and decision tree. --- @@ -28,7 +54,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/)) @@ -173,176 +199,49 @@ Squad answers directly without spawning an agent. ## Response Modes -Not every request needs the full agent machinery. Squad uses tiered response modes to balance speed and depth: - -| Mode | Approximate Time | What Happens | When Used | -|------|-------------------|-------------|-----------| -| **Direct** | ~2–3s | Coordinator answers from memory/context — no agent spawned | Quick factual questions, status checks | -| **Lightweight** | ~8–12s | Agent spawned with reduced overhead (no charter/history/decisions reads) | Simple tasks with known inputs | -| **Standard** | ~25–35s | Full agent spawn with charter, history, and decisions | Most work requests | -| **Full** | ~40–60s | Multi-agent parallel spawn with design review ceremony | Complex multi-domain tasks | +Squad automatically picks the right response speed based on your request complexity. Direct answers take seconds, full agent spawns take longer but deliver deeper reasoning and parallel work. You don't control the mode — Squad routes based on what the task needs. -The coordinator selects the mode automatically. You don't need to specify it. More complex tasks naturally take longer because more agents are working in parallel and reading more context. +→ [Full guide: Response Modes](features/response-modes.md) --- ## Memory System -Squad's memory is layered. Knowledge grows with use. - -### Personal memory: `history.md` +Squad's memory is layered — personal agent histories, shared team decisions, and reusable skills. Knowledge compounds over sessions. After a few sessions, agents stop asking questions they've already answered. Mature projects carry full architecture knowledge and decision history. -Each agent has its own `history.md` in `.ai-team/agents/{name}/`. After every session, agents append what they learned — architecture decisions, conventions, user preferences, key file paths. This file is read only by that agent. - -After a few sessions, agents stop asking questions they've already answered. - -### Shared memory: `decisions.md` - -Team-wide decisions live in `.ai-team/decisions.md`. Every agent reads this before working. Decisions are captured in three ways: - -1. **From agent work** — agents write decisions to `.ai-team/decisions/inbox/{name}-{slug}.md` -2. **From user directives** — when you say "always use..." or "never do..." -3. **Scribe merges** — the Scribe agent consolidates inbox entries into the canonical file, deduplicates, and propagates updates to affected agents - -### Skills: `.ai-team/skills/` - -Skill files (`SKILL.md`) encode reusable knowledge. They come in two varieties: - -- **Starter skills** — bundled at init (e.g., squad conventions) -- **Earned skills** — written by agents from real work, with a confidence lifecycle: `low → medium → high` - -Agents read relevant skill files before working on a task. - -### How memory compounds - -| Stage | What agents know | -|-------|-----------------| -| 🌱 First session | Project description, tech stack, user name | -| 🌿 After a few sessions | Conventions, component patterns, API design, test strategies | -| 🌳 Mature project | Full architecture, tech debt map, regression patterns, performance conventions | +→ [Full guide: Memory System](features/memory.md) --- ## Export and Import -### Export your squad - -```bash -npx github:bradygaster/squad export -``` - -Creates `squad-export.json` — a portable snapshot of your entire team: agents, casting state, skills, and accumulated knowledge. - -Use this to: -- Back up your team before major changes -- Share a trained team with a colleague -- Move a team to a different repo - -### Import a squad - -```bash -npx github:bradygaster/squad import squad-export.json -``` - -Imports the snapshot into the current repo. Squad handles collision detection — if agents with the same names already exist, it warns you. - -Use `--force` to archive existing agents and replace them: - -```bash -npx github:bradygaster/squad import squad-export.json --force -``` +Export creates a portable snapshot of your entire team — agents, knowledge, skills. Import brings that snapshot into another repo. Squad handles collision detection and splits imported knowledge into portable learnings and project-specific context automatically. -During import, agent histories are split into **portable knowledge** (general learnings that transfer) and **project-specific learnings** (which stay context-tagged). This means imported agents bring their skills without assuming your project works the same way. +→ [Full guide: Export and Import](features/export-import.md#export--import) --- ## GitHub Issues Mode -Squad integrates with GitHub Issues via the `gh` CLI for issue-driven development. +Squad integrates with GitHub Issues for issue-driven development. Connect to a repo, view the backlog, assign issues to agents, and Squad handles branch creation, implementation, PR creation, and review feedback. Agents link work to issues automatically. -### Connect to a repository - -``` -> Connect to myorg/myrepo -``` - -Squad stores the issue source and makes the repository's issues available to the team. - -### View the backlog - -``` -> Show the backlog -``` - -Squad displays open issues in a table format. - -### Assign an issue to an agent - -``` -> Work on #12 -``` - -The appropriate agent picks up the issue. What happens next: - -1. Agent creates a branch with a descriptive name based on the issue -2. Agent does the implementation work -3. Agent opens a PR linked to the issue - -### Handle PR review feedback - -``` -> There's review feedback on PR #3 -``` - -The relevant agent reads the review comments and addresses them. - -### Merge completed work - -``` -> Merge it -``` - -The PR is merged and the linked issue is closed. - -### Check remaining work - -``` -> What's left? -``` - -Squad refreshes the backlog and shows remaining open issues. +→ [Full guide: GitHub Issues Mode](features/github-issues.md#github-issues-mode) --- ## PRD Mode -If you have a product requirements document, paste the spec directly: +Paste your product requirements document directly into Squad. The Lead agent decomposes the spec into discrete work items, assigns them to the right agents, and the team works in parallel. Specs become trackable tasks automatically. -``` -> Here's what we're building: -> -> [paste your PRD or spec here] -``` - -The Lead agent decomposes the spec into discrete work items. These become trackable tasks that Squad distributes across the team. Each work item gets assigned to the agent best suited for it, and the team works them in parallel where possible. +→ [Full guide: PRD Mode](features/prd-mode.md#prd-mode) --- ## Human Team Members -Not every team member needs to be an AI agent. You can add human team members to the roster: - -``` -> Add Sarah as a human team member — she handles design reviews -``` +Not every team member needs to be an AI agent. Add humans to the roster for decisions that require a real person — design sign-off, security review, product approval. Squad pauses when work is routed to a human and reminds you if they haven't responded. -Human team members appear in the roster with a distinct badge. When work is routed to a human: - -- **Squad pauses** and tells you a human needs to act -- **Stale reminders** trigger if the human hasn't responded after a configurable period -- Humans can serve as **reviewers** in the reviewer protocol - -This is useful for teams where certain decisions (design sign-off, security review, product approval) require a real person. +→ [Full guide: Human Team Members](features/human-team-members.md#human-team-members) --- @@ -352,54 +251,15 @@ Your squad can notify you when they need input — send instant pings to Teams, **Setup is quick:** Configure an MCP notification server (takes 5 minutes), and agents automatically know when to ping you. -See [Notifications Guide](features/notifications.md) for platform-specific setup and examples. For MCP configuration details, see [MCP Setup Guide](features/mcp.md). +See [Notifications Guide](features/notifications.md#quick-start-teams-simplest-path) for platform-specific setup and examples. For MCP configuration details, see [MCP Setup Guide](features/mcp.md#step-by-step-cli-setup). --- ## Ceremonies -Ceremonies are structured team meetings. Squad ships with two default ceremonies: - -### Design Review (automatic) - -**Triggers before** multi-agent tasks involving 2+ agents modifying shared systems. The Lead facilitates, spawning each relevant agent to get their perspective on interfaces, risks, and contracts before work begins. - -``` -> Team, rebuild the authentication system - -📋 Design Review completed — facilitated by Ripley - Decisions: 3 | Action items: 4 - Agreed on JWT format, session storage strategy, and endpoint contracts -``` - -### Retrospective (automatic) +Ceremonies are structured team meetings. Squad ships with two default ceremonies — Design Review (triggers before multi-agent work) and Retrospective (triggers after failures). You can trigger ceremonies manually, create custom ones, or disable them. Configuration lives in `.ai-team/ceremonies.md`. -**Triggers after** build failures, test failures, or reviewer rejections. The Lead facilitates a focused root-cause analysis. - -``` -📋 Retrospective completed — facilitated by Ripley - Decisions: 2 | Action items: 3 - Root cause: missing null check in API response parser -``` - -### Manual ceremonies - -You can trigger any ceremony on demand: - -``` -> Run a retro -> Run a design meeting before we start -``` - -You can also create, disable, or skip ceremonies: - -``` -> Add a ceremony for code reviews -> Disable retros -> Skip the design review for this task -``` - -Ceremony configuration lives in `.ai-team/ceremonies.md`. +→ [Full guide: Ceremonies](features/ceremonies.md#ceremonies) --- @@ -438,7 +298,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. @@ -466,14 +326,9 @@ Agents are never deleted. Their charter and history move to `.ai-team/agents/_al ## Reviewer Protocol -Agents with review authority (typically Tester and Lead) can **reject** work. On rejection: - -1. The original author is **locked out** — they cannot revise their own rejected work. -2. A **different agent** must handle the revision. -3. If the revision is also rejected, the revision author is locked out too, and a third agent must take over. -4. If all eligible agents are locked out, Squad escalates to you. +Agents with review authority can reject work. On rejection, the original author is locked out and a different agent must handle the revision. This prevents the common failure mode where an agent keeps fixing its own work in circles. -This prevents the common failure mode where an agent keeps "fixing" its own work in circles. +→ [Full guide: Reviewer Protocol](features/reviewer-protocol.md#reviewer-rejection-protocol) --- diff --git a/docs/src/content/docs/guide/building-extensions.md b/docs/src/content/docs/guide/building-extensions.md new file mode 100644 index 000000000..89db805c1 --- /dev/null +++ b/docs/src/content/docs/guide/building-extensions.md @@ -0,0 +1,126 @@ +# Building extensions + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +You've decided your idea is a Squad Extension (Layer 2). Now build one in five minutes. + +--- + +## What is an extension? + +An extension is a reusable collection of skills, ceremonies, and directives that any team can install. It lives outside Squad core, packaged as a GitHub repository or marketplace plugin. Extensions let you codify workflows (the client-delivery pattern), domain expertise (Azure deployment strategies), or testing ceremonies that other teams benefit from. + +--- + +## Extension structure + +``` +my-extension/ +├── skills/ +│ ├── SKILL1.md +│ └── SKILL2.md +├── ceremonies/ +│ └── CEREMONY.md +├── directives/ +│ └── DIRECTIVE.md +└── README.md +``` + +--- + +## Build one + +**Step 1: Create a repo** + +```bash +mkdir my-extension +cd my-extension +git init +``` + +**Step 2: Add a skill** + +Create `skills/example-skill.md`: + +```markdown +# Example Skill + +**When to use:** You need to do X. + +## Context + +Brief problem statement. + +## Steps + +1. Do the first thing +2. Do the second thing +3. Done +``` + +**Step 3 (optional): Add a ceremony** + +Create `ceremonies/code-review.md` following Squad ceremony format (decision gate, verdicts, escalation). + +**Step 4: Write the README** + +Explain the problem, installation, and usage: + +```markdown +# My Extension + +Codifies client-delivery workflows for consulting teams. + +## Install + +squad plugin install github/my-org/my-extension + +## What's Inside + +- **discovery-interview** skill — clarify requirements +- **evidence-bundler** skill — collect test results +- **plan-review** ceremony — gate for approval +``` + +**Step 5: Test locally** + +Copy your extension directory into `.squad/skills/`, `.squad/ceremonies/`, and `.squad/directives/`. Load your Squad session and verify the skills appear and work as expected. + +--- + +## Share it + +Push to GitHub: + +```bash +git add . +git commit -m "Initial extension: my-extension" +git push +``` + +Register with a marketplace or pin directly by repository URL: + +``` +squad plugin install github/my-org/my-extension +``` + +--- + +## Real examples + +- **Client-delivery workflow** ([RFC #328](https://github.com/bradygaster/squad/issues/328)) — discovery, research, multi-round review with evidence gates +- **Azure infrastructure patterns** — VM provisioning, Cosmos DB design, monitoring rules +- **Knowledge library skills** — document structured analysis, reference synthesis + +--- + +## Related docs + +- [Extensibility guide](./extensibility.md#decision-tree) — Where does your idea belong? (decision tree) +- [Plugin Marketplace](../features/plugins.md) — How teams discover and install your extension +- [Skills](../features/skills.md) — How to author reusable skills +- [Ceremonies](../features/ceremonies.md) — How to define decision gates and review rituals + +--- + +**Ready to share?** [Open a discussion](https://github.com/bradygaster/squad/discussions) in the Squad community. 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/src/content/docs/guide/extensibility.md b/docs/src/content/docs/guide/extensibility.md new file mode 100644 index 000000000..a9a70b304 --- /dev/null +++ b/docs/src/content/docs/guide/extensibility.md @@ -0,0 +1,130 @@ +# Extensibility guide + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +Where does your change idea belong? Squad core, marketplace plugin, or team config? + +**Key principle:** Squad core stays small. Most ideas are skills, ceremonies, or directives. + +--- + +## The three layers + +| Layer | What lives here | Who changes it | Distribution | +|-------|----------------|----------------|--------------| +| **Squad Core** | Coordinator behavior, routing logic, reviewer protocol | Squad maintainers only | npm releases | +| **Squad Extension** | Reusable patterns (skills, ceremonies, workflows) | Plugin authors | Marketplace plugins | +| **Team Configuration** | Decisions unique to THIS team | The team itself | `.squad/` files | + +--- + +## Decision tree + +``` +┌─ Does it change HOW the coordinator routes, spawns, or enforces? +│ +├─ YES → Squad Core +│ └─ Examples: New coordinator modes, reviewer protocol changes +│ Action: Open an RFC issue +│ +└─ NO → Continue... + │ + ┌─ Could OTHER teams benefit? + │ + ├─ YES → Squad Extension (plugin) + │ └─ Examples: Client-delivery workflow, Azure skills, TDD ceremonies + │ Action: Build a plugin + │ + └─ NO → Team Configuration + └─ Examples: YOUR git workflow, YOUR build process, YOUR routing rules + Action: Update `.squad/` files +``` + +**Heuristic:** "Squad should..." → check if it's really "My team should..." or "Teams using X should...". + + + +--- + +## Worked example: Client-delivery RFC + +[RFC #328](https://github.com/bradygaster/squad/issues/328) proposed a sophisticated client-delivery workflow: discovery interviews, research sprints, multi-round review with `SHIP`/`NEEDS_WORK`/`BLOCKED` verdicts, evidence bundles. + +**The realization:** It maps entirely to existing Squad primitives. No core changes needed. + +**Where it belongs:** Layer 2 (Squad Extension) + +This workflow is a reusable pattern any team could adopt — perfect as a marketplace plugin. + +**Plugin structure:** +``` +client-delivery-workflow/ +├── skills/ +│ ├── discovery-interview/ # Clarify requests, extract requirements +│ ├── research-sprint/ # Propose directions, score options +│ └── evidence-bundler/ # Collect test results, logs, screenshots +├── ceremonies/ +│ ├── plan-review.md # Gate: approve before implementation +│ └── implementation-review.md # Gate: verify evidence +└── directives/ + └── multi-round-review.md # Policy: 2 NEEDS_WORK rounds max +``` + +**Usage:** +```bash +squad plugin install github/awesome-copilot/client-delivery-workflow +``` + +**Lesson:** Most sophisticated workflows are compositions of primitives, not core features. + +--- + +## When to escalate to core + +You likely need a core change if: + +- **New coordinator mode** — Example: `validate` mode that runs checks before `assign` +- **Routing logic change** — Example: Route based on agent workload, not labels +- **Reviewer protocol change** — Example: Conditional approvals ("approved if tests pass") +- **Global enforcement rule** — Example: Block merges if evidence missing +- **Skill needs coordinator data** — Example: Access to agent spawn history + +You DON'T need core if: + +- **Workflow pattern** → Build a plugin (skills + ceremonies) +- **Domain expertise** → Write a skill +- **Team process** → Add a ceremony to `.squad/ceremonies.md` +- **Reusable templates** → Build a plugin +- **Configuring existing behavior** → Update `.squad/routing.md` + +--- + +## Build an extension + +Ready to build? See [Building extensions](./building-extensions.md) for a five-minute walkthrough. + +--- + +## Summary + +1. **Start with the decision tree** — Most ideas are Layer 2 or 3 +2. **Default to team config** — Unique to your team? → `.squad/` +3. **Build a plugin if reusable** — Other teams benefit? → Package and share +4. **Escalate to core rarely** — Need coordinator/routing changes? → Open an RFC + +**When in doubt:** Start with team config. Copy-pasting to other teams? Promote to plugin. Plugins repeatedly hitting limits? Signal for core change. + +--- + +## Related documentation + +- [Plugin Marketplace](../features/plugins.md) — How to browse, install, and share plugins +- [Skills](../features/skills.md) — How to write skills for your team or plugins +- [Ceremonies](../features/ceremonies.md) — How to define team meetings and gates +- [Routing](../features/routing.md) — How to configure work assignment rules +- [Building extensions](./building-extensions.md) — Step-by-step guide to building and sharing extensions +- [Contributing](https://github.com/bradygaster/squad/blob/main/CONTRIBUTING.md) — How to propose changes to Squad core + +--- + +**Questions?** [Open an issue](https://github.com/bradygaster/squad/issues/new) or join the discussion in the Squad community. diff --git a/docs/src/content/docs/guide/faq.md b/docs/src/content/docs/guide/faq.md new file mode 100644 index 000000000..00279363b --- /dev/null +++ b/docs/src/content/docs/guide/faq.md @@ -0,0 +1,277 @@ +# Frequently asked questions + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + + +Common questions, troubleshooting tips, and clarifications based on community feedback. Can't find your answer? [Open an issue](https://github.com/bradygaster/squad/issues/new). + +--- + +## Which CLI should I use? + +**Short answer:** Use **GitHub Copilot CLI** for day-to-day work. Use **Squad CLI** for setup, diagnostics, and specific features. + +**Why GitHub Copilot CLI?** +- Full agent spawning capabilities +- Access to all Squad features through natural conversation +- Model selection and background execution +- No manual commands — just describe what you need + +**When to use Squad CLI:** +- Initial setup: `squad init` +- Diagnostics: `squad doctor` +- Continuous triage: `squad triage --interval 10` +- Aspire dashboard: `squad aspire` +- Export/import: `squad export` and `squad import` +- Remote phone access: `squad start --tunnel` + +**Common workflow pattern:** +```bash +# Terminal 1: Run continuous triage +squad triage --interval 10 + +# Terminal 2: Work with your team +gh copilot +> @squad what issues are ready to work? +``` + +For a detailed feature comparison, see [Client Compatibility Matrix](../scenarios/client-compatibility.md). + +--- + +## Why doesn't `gh issue edit --add-assignee "@copilot"` work? + +**Problem:** Running `gh issue edit --add-assignee "@copilot"` (or variants like `copilot-swe-agent[bot]`) fails locally, even with a Personal Access Token. + +**Why this happens:** The GitHub Copilot coding agent is a bot account. Bot accounts cannot be assigned to issues via the GitHub CLI in the same way as human users — the GitHub API restricts direct assignment of bot accounts through standard endpoints. + +**Recommended workaround:** Use **label-based assignment** through the GitHub Actions workflow: + +1. Add the `squad:copilot` label to the issue: + ```bash + gh issue edit --add-label "squad:copilot" + ``` + +2. The auto-assign workflow (`.github/workflows/squad-copilot-auto-assign.yml`) detects the label and assigns @copilot automatically. + +**Prerequisites for auto-assign:** +- You must create a **GitHub Classic Personal Access Token** with `repo` scope +- Add it as a repository secret: `gh secret set COPILOT_ASSIGN_TOKEN` +- The workflow uses this token to perform the assignment on your behalf + +See [Copilot Coding Agent](../features/copilot-coding-agent.md) for full setup instructions. + +--- + +## I don't see anything on the Aspire dashboard + +**Problem:** You ran `squad aspire` and opened the dashboard, but no telemetry is showing up. + +**Why this happens:** The Aspire dashboard integration **requires the Squad CLI**. It is not available when using GitHub Copilot CLI directly. + +**How to fix:** +1. Ensure you started Aspire with the Squad CLI: + ```bash + squad aspire + ``` + +2. Confirm the container is running: + ```bash + docker ps | grep aspire-dashboard + ``` + +3. Look for the dashboard URL in the output (usually `http://localhost:18888`) + +4. Run a Squad CLI command that generates telemetry: + ```bash + squad doctor + squad triage + ``` + +5. Refresh the Aspire dashboard — you should see traces, metrics, and logs appear + +**Note:** GitHub Copilot CLI sessions do **not** send telemetry to Aspire. Only Squad CLI commands emit OpenTelemetry data to the dashboard. + +See [Using Squad with the Aspire Dashboard](../scenarios/aspire-dashboard.md) for details. + +--- + +## `squad doctor` complains about absolute path for teamRoot + +**Problem:** Running `squad doctor` shows a warning like: + +``` +⚠ teamRoot uses absolute path — consider making it relative +``` + +**Why this matters:** Absolute paths (e.g., `C:\Users\me\squad\` or `/Users/me/squad/`) break portability. If you share the squad with a teammate or clone it to a new machine, the absolute path won't resolve correctly. + +**How to fix:** Make the `teamRoot` path **relative to the project root**. + +**Example — Before (absolute):** +```json +{ + "teamRoot": "C:\\Users\\me\\repos\\my-team\\.squad" +} +``` + +**Example — After (relative):** +```json +{ + "teamRoot": ".squad" +} +``` + +**For linked teams (dual-root mode):** + +If your project links to a remote team repository: + +```json +{ + "teamRoot": "../team-repo/.squad" +} +``` + +The path should be relative to your **project root** (where `.squad/` or `squad.config.ts` lives), not to the `.squad/` directory itself. + +**Verify the fix:** +```bash +squad doctor +``` + +You should see `✓ teamRoot is relative` or no warning. + +--- + +## Can I use Squad CLI and GitHub Copilot CLI at the same time? + +Yes! They complement each other: + +- **Squad CLI** provides infrastructure: triage, Aspire observability, export/import, diagnostics +- **GitHub Copilot CLI** provides conversational interface to your team + +**Recommended setup:** +- Run `squad triage --interval 10` in a dedicated terminal (or as a cron job / GitHub Action) +- Use `gh copilot` (or `@squad` in VS Code) for all team interactions +- Use `squad doctor` or `squad aspire` for diagnostics when needed + +Both CLIs read and write the same `.squad/` directory, so state stays synchronized. + +--- + +## What's the difference between Ralph and triage? + +**Ralph** and **triage** are different names for the same functionality: + +- **`squad ralph`** is the legacy command name +- **`squad triage`** is the new primary command name (as of v0.8.26) +- Both commands do the same thing: monitor GitHub issues, apply routing rules, and assign work to team members + +**Migration path:** +- Existing scripts using `squad ralph` will continue to work (it's an alias) +- New projects should use `squad triage` in documentation and automation +- The `ralph/` directory in `.squad/` remains unchanged for backward compatibility + +--- + +## How do I add a new agent to my squad? + +**In conversation (recommended):** + +``` +gh copilot +> @squad I want to add a new agent +> Role: Security specialist +> Name: Guardian +> Expertise: OWASP, dependency scanning, secrets detection +``` + +Squad will create the charter, update the team roster, and add routing rules. + +**Manual creation:** + +1. Create a charter file in `.squad/agents//charter.md` +2. Update `.squad/team.md` to include the new agent in the roster +3. Add routing rules in `.squad/routing.md` (if applicable) +4. Optionally add a history file in `.squad/agents//history.md` + +See [Team Setup](../features/team-setup.md) for details. + +--- + +## What happens if I run `squad init` twice? + +Nothing breaks! `squad init` is **idempotent** — it's safe to run multiple times. + +**What it does:** +- Checks if `.squad/` exists; if yes, does nothing +- Copies missing templates from `.ai-team-templates/` to `.squad/` +- Updates `.github/workflows/` with Squad Actions (skips existing files) +- Adds `.github/agents/squad.agent.md` if missing + +**Use cases:** +- Recover from partial initialization +- Update workflows after a Squad upgrade +- Add missing templates without overwriting custom changes + +--- + +## Can I use Squad without GitHub Issues? + +Yes, but with limitations. + +**What works without GitHub Issues:** +- Conversational team interaction (`@squad`, `gh copilot`) +- Agent spawning and parallel execution +- Memory, decisions, and knowledge sharing +- Skills and ceremonies +- Export/import for portability + +**What requires GitHub Issues:** +- Ralph/triage auto-assignment +- Issue-driven development workflows +- Project board integration +- Label-based routing +- Copilot coding agent auto-assignment + +If you're using GitLab, see [GitLab Issues](../features/gitlab-issues.md) for integration options. + +--- + +## How do I reset my squad without losing decisions? + +**Option 1: Archive and start fresh** +```bash +# Export current state +squad export --out backup-$(date +%Y%m%d).json + +# Remove .squad/ +rm -rf .squad/ + +# Reinitialize +squad init +``` + +Manually copy decisions from the backup JSON or `.squad/decisions.md` if you archived it separately. + +**Option 2: Selective cleanup** +```bash +# Remove agent state but keep team structure +rm -rf .squad/agents/*/history.md +rm -rf .squad/sessions/ + +# Keep .squad/decisions.md, .squad/team.md, .squad/routing.md +``` + +See [Disaster Recovery](../scenarios/disaster-recovery.md) for more recovery patterns. + +--- + +## Where should I report bugs or request features? + +[Open an issue on GitHub](https://github.com/bradygaster/squad/issues/new) with: +- **Environment:** OS, Node.js version, Squad version (`squad --version`) +- **Reproduction steps:** What you ran, what happened, what you expected +- **Output:** Copy the full terminal output, including any errors + +For questions or discussions, use [GitHub Discussions](https://github.com/bradygaster/squad/discussions). diff --git a/docs/guide/personal-squad.md b/docs/src/content/docs/guide/personal-squad.md similarity index 87% rename from docs/guide/personal-squad.md rename to docs/src/content/docs/guide/personal-squad.md index 92d7adec3..36f4e1676 100644 --- a/docs/guide/personal-squad.md +++ b/docs/src/content/docs/guide/personal-squad.md @@ -18,7 +18,15 @@ This tutorial walks you through setup, explains what's happening behind the scen Normally, Squad lives inside a single project — `.squad/` in your repo root. Your agents know that project. They don't know your other ones. -A personal squad flips that. Your team identity — agents, charters, skills, casting history — moves to a global directory (`~/.squad/`). Every project you work in can point to it. +A personal squad flips that. Your team identity — agents, charters, skills, casting history — moves to your personal squad directory. Every project you work in can point to it. + +**Personal squad location by platform:** + +| Platform | Path | +|----------|------| +| Linux | `~/.config/squad/` | +| macOS | `~/Library/Application Support/squad/` | +| Windows | `%APPDATA%\squad\` | What that means in practice: @@ -51,7 +59,7 @@ You'll see: ``` ✅ Personal squad initialized. - ~/.squad/ — your global team root + {personal squad directory} — your global team root Agents, skills, and casting will be shared across projects. ``` @@ -65,7 +73,7 @@ squad status ``` Squad Status - Global squad: ~/.squad/ + Global squad: {personal squad directory} Agents: 0 (none cast yet — start a session to form your team) Skills: 0 ``` @@ -85,7 +93,7 @@ Squad detects your global team root and writes a pointer: ``` ✅ Squad initialized. - .squad/config.json → teamRoot: ~/.squad/ + .squad/config.json → teamRoot: {personal squad directory} Team identity inherited from personal squad. Project-local state (decisions, logs) stays here. ``` @@ -100,12 +108,12 @@ Repeat for any project you want connected. Two things were created. Understanding the split is the key to personal squads. -### The global directory: `~/.squad/` +### The global directory: your personal squad This is your **team identity**. It contains: ``` -~/.squad/ +{personal squad directory}/ agents/ — your agent charters and histories casting/ — who's been cast, role assignments skills/ — accumulated knowledge ("always use Zod", "prefer Tailwind") @@ -120,7 +128,7 @@ Inside each connected project, `.squad/config.json` looks like this: ```json { "version": 1, - "teamRoot": "~/.squad/", + "teamRoot": "{personal squad directory}", "projectKey": null } ``` @@ -129,14 +137,14 @@ That `teamRoot` field is the magic. When Squad's resolution system sees it, the | | **Local mode** (default) | **Remote mode** (personal squad) | |---|---|---| -| Team identity | `.squad/` in project | `~/.squad/` (global) | +| Team identity | `.squad/` in project | Personal squad directory (global) | | Decisions & logs | `.squad/` in project | `.squad/` in project | | Agents shared? | No — project only | Yes — across all connected projects | | Skills shared? | No | Yes | In remote mode: -- **Team identity** (agents, charters, skills, casting) → loaded from `~/.squad/` +- **Team identity** (agents, charters, skills, casting) → loaded from your personal squad directory - **Project-local state** (decisions, logs, orchestration-log) → stays in this project's `.squad/` The resolution system walks up directories looking for `.squad/`. When it finds one with a `teamRoot` in `config.json`, it switches to remote mode — pulling team identity from the external path while keeping project state local. @@ -251,7 +259,7 @@ Set a directive once: 📌 Captured. Linting required before task completion. ``` -That directive is now in `~/.squad/` — every project, every session. Your agents enforce it everywhere. You set the standard once and it sticks. +That directive is now in your personal squad directory — every project, every session. Your agents enforce it everywhere. You set the standard once and it sticks. Over time, your personal squad becomes an opinionated workflow engine. Not because you configured it that way — because you worked with it and it learned. @@ -259,12 +267,12 @@ Over time, your personal squad becomes an opinionated workflow engine. Not becau ## 8. Use Case: Skills That Grow Everywhere -Skills accumulate in `~/.squad/skills/`. Every project contributes. +Skills accumulate in your personal squad directory under `skills/`. Every project contributes. After a few weeks: ``` -~/.squad/skills/ +{personal squad directory}/skills/ always-use-zod.md prefer-tailwind.md cursor-pagination.md @@ -292,7 +300,7 @@ What works well today: - **Consult mode** — bring your team to projects you don't own, invisibly ([docs](../features/consult-mode.md)) What's still rough: -- No sync mechanism between machines yet — `~/.squad/` is local to your machine +- No sync mechanism between machines yet — your personal squad directory is local to your machine - Project keys aren't used for anything yet (that `null` in config.json) - No UI for browsing your global skills or agent histories (it's files for now) @@ -303,10 +311,10 @@ We're building in the open. If something feels off, [open an issue](https://gith ## Tips - **Start with one project.** Get comfortable with the personal squad on one repo before connecting others. The value compounds, but so does confusion if something's misconfigured. -- **Commit project `.squad/` but not global `~/.squad/`.** The project-local state (decisions, logs) belongs in version control. Your global identity is personal — keep it out of repos. +- **Commit project `.squad/` but not personal squad directory.** The project-local state (decisions, logs) belongs in version control. Your global identity is personal — keep it out of repos. - **Check status anytime.** `squad status` shows your global squad directory and which projects are connected. - **Skills are the payoff.** The more projects you work across, the more skills accumulate. After a month, your agents have a real knowledge base tailored to how *you* build software. -- **It's just files.** `~/.squad/` is a directory on your machine. You can browse it, edit it, back it up, copy it to another machine manually. No magic, no cloud, no lock-in. +- **It's just files.** Your personal squad directory is a folder on your machine. You can browse it, edit it, back it up, copy it to another machine manually. No magic, no cloud, no lock-in. - **Global install matters.** `npm install -g @bradygaster/squad-cli` gives you the `squad` command everywhere. Without it, you'd need `npx` in each project. Global CLI + global squad = full portability. --- 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..5e82a47fa --- /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. Returns platform-specific path: `~/.config/squad/` on Linux, `~/Library/Application Support/squad/` on macOS, `%APPDATA%\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 80% rename from docs/reference/cli.md rename to docs/src/content/docs/reference/cli.md index a91fbdbd0..73c6529da 100644 --- a/docs/reference/cli.md +++ b/docs/src/content/docs/reference/cli.md @@ -28,7 +28,9 @@ squad init |---------|-------------|:------------------:| | `squad` | Enter interactive shell (no args) | No | | `squad init` | Initialize Squad in the current repo (idempotent — safe to run multiple times) | No | -| `squad init --global` | Create a personal squad at `~/.squad/` | No | +| `squad init --global` | Create a personal squad in your platform-specific directory | No | +| `squad init --sdk` | Generate typed `squad.config.ts` with `useRole()` calls | No | +| `squad init --roles` | Include base role catalog (Lead, Backend, etc.) instead of universe casting | No | | `squad init --mode remote ` | Initialize linked to a remote team root (dual-root mode) | No | | `squad start [--tunnel] [--port N] [--command cmd]` | Start Copilot with remote phone access via PTY and WebSocket | No | | `squad status` | Show which squad is active and why | Yes | @@ -49,7 +51,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 | @@ -239,7 +241,7 @@ 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/`) +3. Personal squad directory (platform-specific: `~/.config/squad/` on Linux, `~/Library/Application Support/squad/` on macOS, `%APPDATA%\squad\` on Windows) 4. Global CLI default (fallback only) First match wins. @@ -268,10 +270,11 @@ squad doctor This performs a comprehensive diagnostic check of your Squad setup, validating: - `.squad/` directory structure -- Required configuration files (team.md, routing.md, etc.) -- Agent definitions and capabilities -- File permissions and integrity -- Integration with GitHub and Copilot +- `config.json` validity and `teamRoot` configuration (if present) +- Team root resolution (remote mode) +- Required files: `team.md`, `routing.md`, `decisions.md` +- `agents/` directory and agent count +- `casting/registry.json` integrity ### Usage Examples @@ -289,14 +292,46 @@ git clone my-project && cd my-project && squad doctor ### Example Output ``` -✓ .squad/ directory exists -✓ team.md is readable and valid -✓ 4 agents registered -⚠ skills/ directory is empty — consider adding documentation -✓ .gitattributes rules applied +🩺 Squad Doctor +═══════════════ + +Mode: local + +✅ .squad/ directory exists — directory present +✅ team.md found with ## Members header — file present, header found +✅ routing.md found — file present +✅ agents/ directory exists — directory present (4 agents) +✅ casting/registry.json exists — file present, valid JSON +✅ decisions.md exists — file present + +Summary: 6 passed, 0 failed, 0 warnings +``` + +The doctor always exits cleanly (exit code 0) because it's a diagnostic tool, not a gate. Use it to troubleshoot setup issues, validate team state, or run before opening an issue on GitHub. + +For a full reference of every check, warning, and fix, see [Troubleshooting: `squad doctor` warnings and failures](../scenarios/troubleshooting.md#squad-doctor-warnings-and-failures). + +### Common Issues + +**Absolute path warning for teamRoot:** + +If you see `⚠ teamRoot uses absolute path — consider making it relative`, it means your `squad.config.ts` or `.squad/config.json` contains an absolute path like `C:\Users\me\squad\` or `/Users/me/squad/`. This breaks portability. + +**Fix:** Make the path relative to your project root: +```json +{ + "teamRoot": ".squad" +} +``` + +For linked teams (dual-root mode), use a relative path: +```json +{ + "teamRoot": "../team-repo/.squad" +} ``` -The doctor always exits cleanly (no error code) because it's a diagnostic tool, not a gate. Use it to troubleshoot setup issues, validate team state, or run before opening an issue on GitHub. +See [FAQ: squad doctor complains about absolute path for teamRoot](../guide/faq.md#squad-doctor-complains-about-absolute-path-for-teamroot) for details. --- diff --git a/docs/reference/config.md b/docs/src/content/docs/reference/config.md similarity index 69% rename from docs/reference/config.md rename to docs/src/content/docs/reference/config.md index 359c1d250..eb4654c21 100644 --- a/docs/reference/config.md +++ b/docs/src/content/docs/reference/config.md @@ -85,6 +85,46 @@ Commit this directory. It's your team's brain. Anyone who clones the repo gets t --- +## .squad/ — Required vs Optional Files + +`squad init` creates a working team. Here's what's required and what's optional. + +### Required Files + +These are always created by `squad init`. The loader expects them. + +| File | Purpose | Can You Edit? | +|------|---------|---------------| +| `.squad/team.md` | Team roster — loader requires it | Yes | +| `.squad/decisions.md` | Shared decision log — agents read before work | Yes (append only) | +| `.squad/routing.md` | Work assignment rules | Yes | +| `.squad/ceremonies.md` | Team meeting definitions | Yes | +| `.squad/config.json` | SDK settings (teamRoot, version) | Rarely | +| `.squad/agents/{name}/charter.md` | Agent identity — compiled at spawn | Yes | +| `.squad/agents/{name}/history.md` | Agent learnings — grows over time | Append only | +| `.squad/identity/now.md` | Current team focus | Auto-updated | +| `.squad/identity/wisdom.md` | Accumulated team patterns | Auto-updated | +| `.gitattributes` | Merge drivers for append-only files | Merge rules only | + +### Optional Files + +These are created only when you opt in during init. + +- **`.squad/templates/`** — SDK templates, overwritten on upgrade +- **`.github/workflows/*.yml`** — CI/CD workflows (opt-in: `--include-workflows`) +- **`.copilot/mcp-config.json`** — MCP server config (opt-in: `--include-mcp-config`) + +> ⚠️ **Hard rule:** Squad NEVER writes temp files, logs, or memory to your repo root. All team state lives in `.squad/` only. Your project tree stays clean. + +### Quick Recovery + +```bash +squad doctor # Check for issues +rm -rf .squad && squad init # Full reset (back up agents/decisions first) +``` + +--- + ## Routing Rules Control which agent gets which work. Edit `.squad/routing.md` or configure in `squad.config.ts`: @@ -145,7 +185,7 @@ Squad finds `.squad/` by walking up: 1. Current directory (`./.squad/`) 2. Parent directories (up to project root) -3. Home directory (`~/.squad/`) +3. Personal squad directory (platform-specific: `~/.config/squad/` on Linux, `~/Library/Application Support/squad/` on macOS, `%APPDATA%\squad\` on Windows) 4. Global CLI default (fallback) First match wins. 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 98% rename from docs/reference/sdk.md rename to docs/src/content/docs/reference/sdk.md index bff98e66c..a45744c9c 100644 --- a/docs/reference/sdk.md +++ b/docs/src/content/docs/reference/sdk.md @@ -24,12 +24,12 @@ Find `.squad/` directories on disk. | Function | Description | |----------|-------------| | `resolveSquad(startPath?)` | Find `.squad/` walking up from `startPath` (throws if not found) | -| `resolveGlobalSquadPath()` | Get `~/.squad/` path (`%USERPROFILE%\.squad\` on Windows) | +| `resolveGlobalSquadPath()` | Get personal squad directory path (platform-specific) | | `ensureSquadPath(startPath?)` | Like `resolveSquad`, but creates `.squad/` if missing | ```typescript const squadPath = resolveSquad(); // '/home/user/project/.squad' -const globalPath = resolveGlobalSquadPath(); // '/home/user/.squad' +const globalPath = resolveGlobalSquadPath(); // Platform-specific: ~/.config/squad/ (Linux), ~/Library/Application Support/squad/ (macOS), %APPDATA%\squad\ (Windows) const safePath = ensureSquadPath(); // Creates if needed ``` 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/src/content/docs/sample-prompts.md b/docs/src/content/docs/sample-prompts.md new file mode 100644 index 000000000..b3a73fee5 --- /dev/null +++ b/docs/src/content/docs/sample-prompts.md @@ -0,0 +1,412 @@ +# Sample Prompts + +Ready-to-use prompts for Squad. Copy any prompt, open Copilot, select **Squad**, and paste it in. + +--- + +## Quick Builds + +Small projects that ship in a single session. Good for parallel fan-out and fast iteration. + +--- + +### 1. CLI Pomodoro Timer + +``` +I'm building a cross-platform CLI pomodoro timer in Python: +- Configurable work/break intervals (25/5/15 defaults) +- Persistent stats tracker (local JSON) +- Desktop notifications (macOS, Windows, Linux) +- Focus mode: blocks domains via /etc/hosts (with undo) +- --report flag for weekly stats table + +Set up the team. I want this done fast — everyone works at once. +``` + +**What it demonstrates:** +- Parallel fan-out on a small, well-scoped project +- Backend handles timer logic while systems agent tackles cross-platform notifications +- Tester writes test cases from spec while implementation is in flight + +--- + +### 2. Markdown Static Site Generator + +``` +Zero-dependency static site generator in Node.js: markdown→HTML with built-in template, generates index page, outputs to dist/. Support front matter (title, date, tags), tag index pages, RSS feed. No frameworks — just fs, path, and a custom markdown parser. + +Set up the team and start building. +``` + +**What it demonstrates:** +- Agents own distinct pipeline components (parser, template engine, RSS, file I/O) +- Tester writes test cases from spec while others build in parallel +- Front matter format decisions propagate via decisions.md + +--- + +### 3. Retro Snake Game + +``` +Browser Snake game (vanilla HTML/CSS/JS, no frameworks): +- Canvas rendering at 60fps +- Arrow keys and WASD controls +- Score tracking with localStorage high scores +- Progressive speed increase every 5 points +- Retro CRT-style CSS filters +- Mobile: touch swipe controls +- Sound effects via Web Audio API + +Start building — I want to play in 20 minutes. +``` + +**What it demonstrates:** +- Frontend, audio, and input handling built in parallel +- Tester writes Playwright tests while game is under construction +- Fast iteration with visible progress across agents + +--- + +### 4. Turn-by-Turn Text Adventure Engine + +``` +Text-based adventure engine in TypeScript: +- Load worlds from JSON (rooms, items, NPCs, transitions) +- Command parser: go [dir], look, take [item], use [item] on [target], talk to [npc], inventory +- Sample adventure: 10 rooms, 5 items, 3 NPCs, 2 puzzles +- Save/load game state to JSON +- Terminal via Node.js with colored output (chalk) +- Narrator voice: descriptions vary by inventory/actions + +Build engine and sample adventure simultaneously. Content writer and engine builder work in parallel. +``` + +**What it demonstrates:** +- Natural split between engine logic and content creation +- Both streams run fully in parallel with shared data format decisions +- Tester writes test cases from spec before implementation completes + +--- + +### 5. Arcane Duel — A Card Battle Game + +``` +Strategic card duel game (browser, inspired by MTG): +- 30+ cards across 4 types: Attack, Defense, Spell, Trap (with mana cost, power, toughness, effects) +- Turn phases: Draw → Main → Combat → End +- Mana system: +1 per turn (max 10), some cards generate bonus mana +- Stack-based spell resolution +- HP: 20 each, win at 0 +- AI opponent with basic strategy +- HTML/CSS grid battlefield showing fields, hands, graveyards +- Card hover preview + +One agent designs cards/balance, another builds engine/rules, another builds UI, tester validates combat math. Go. +``` + +**What it demonstrates:** +- Deep parallelism requiring early data format alignment via decisions.md +- UI scaffolding proceeds while card design is underway +- Scribe's decision propagation becomes critical (mana curve affects engine and AI) + +--- + +### Squad Blog Engine (Meta Demo) + +``` +Static blog engine rendering markdown posts to HTML (no frameworks): + +Input: docs/blog/ markdown with YAML frontmatter (title, date, author, wave, tags, status, hero). + +Output: +- Index page: posts sorted by date, with title/hero/author/tags +- Post pages: clean typography, syntax-highlighted code, responsive tables +- Tag index grouping posts by tag +- Wave navigation: ← Previous | Next → links +- Dark mode toggle (CSS custom properties, localStorage) +- RSS feed (feed.xml) + +Design: Clean, modern, developer-focused. Monospace headings, proportional body. Dark code blocks with copy button. Mobile responsive. Fast — no JS for reading (JS only for dark mode and copy). + +Build parser, template engine, RSS generator, static output (dist/). Include `node build.js` script. Set up team and build in one session. +``` + +**What it demonstrates:** +- Meta-demo where Squad builds its own publishing tool +- All components (parser, templating, RSS, CSS) build in parallel +- Finished product is visual, functional, and self-documenting + +--- + +## Mid-Size Projects + +Real coordination needed. Agents make architectural decisions, share them, and build across multiple rounds. + +--- + +### 6. Cloud-Native E-Commerce Store + +``` +Build an event-driven e-commerce store: +- Product Catalog API (Node.js/Express, PostgreSQL) — CRUD + search +- Order Service (Node.js) — async processing via message queue, payment stubs, events +- Notification Service — listens for order events, emails confirmations +- API Gateway — auth (JWT), rate limiting +- RabbitMQ or in-memory stub for local dev +- React SPA: product grid, cart, checkout + +Each service with its own Dockerfile. Include docker-compose.yml. Orders return 202 Accepted, status polled/pushed via WebSocket. + +Set up a team. One agent per service. Coordinate on API contracts and event schemas early, then build in parallel. +``` + +**What it demonstrates:** +- True microservice parallelism with contract-first coordination +- Event schema decisions must propagate early via Scribe +- API gateway scaffolds while downstream services build independently + +--- + +### 7. Playwright-Tested Dashboard App + +``` +Build a project management dashboard (React + TypeScript, Node.js/Express): +- Kanban board with drag-and-drop (Backlog, In Progress, Review, Done) +- Task creation: title, description, assignee, priority, due date +- Filtering by assignee, priority, status +- Real-time updates via WebSocket +- User auth: login/signup (JWT, bcrypt) +- SQLite + Drizzle ORM + +Full Playwright test suite covering login, CRUD, drag-and-drop, filtering, real-time sync (two browser contexts). Write Gherkin feature files FIRST, then implement Playwright step definitions. Runnable with `npx playwright test`. + +Set up the team. Write Gherkin specs and test skeletons before implementation starts, update as UI takes shape. +``` + +**What it demonstrates:** +- Test-first development with Gherkin specs written before implementation +- Frontend and backend build in parallel while tests scaffold +- Anticipatory work pattern: tests and implementation converge without blocking + +--- + +### 8. GitHub Copilot Extension + +``` +Build a GitHub Copilot Chat extension (Copilot Extensions SDK): +- Act as @code-reviewer agent +- Accept GitHub repo URL or PR number +- Fetch diff via GitHub API, analyze for security (SQL injection, XSS, secrets), performance (N+1 queries), style violations (configurable .code-reviewer.yml) +- Return structured feedback with file-level annotations +- Blackbeard-style SSE streaming response +- Deploy as Vercel serverless function +- Include GitHub App manifest + +Read SDK docs carefully. One agent owns SDK integration/streaming, another owns analysis engine, another owns GitHub API. Set up the team. +``` + +**What it demonstrates:** +- Agents read external SDK docs and build to prescribed patterns +- SDK integration and analysis engine work in parallel with shared interface contract +- Real-world API integration with deployment considerations + +--- + +### 9. .NET Aspire Cloud-Native App + +``` +Build a cloud-native app with .NET Aspire (read https://learn.microsoft.com/en-us/dotnet/aspire/): +- AppHost orchestrating all services +- Blazor Server dashboard: current conditions + 5-day forecast for saved cities +- Weather API service: wraps OpenWeatherMap with Redis caching +- User Preferences service: stores cities (PostgreSQL) +- Background Worker: refreshes cache every 15 minutes +- Service discovery via Aspire (no hardcoded URLs) +- Health checks and OpenTelemetry tracing + +Team organized by Aspire integration: AppHost/discovery, Redis caching, PostgreSQL, Blazor frontend, background worker. Tester validates service discovery and end-to-end data flow. Set up the team. +``` + +**What it demonstrates:** +- Agents specialized by infrastructure component rather than traditional roles +- AppHost coordinates wiring while service agents build independently +- Infrastructure decisions (service names, connection strings) propagate via decisions.md + +--- + +## Large Projects + +Complex coordination, memory, and team size. Multiple rounds, cross-cutting decisions, agents remember earlier work. + +--- + +### 10. Legacy .NET-to-Azure Migration + +``` +Migrate legacy .NET Framework to Azure. Clone: +1. https://github.com/bradygaster/ProductCatalogApp — ASP.NET MVC with WCF SOAP, in-memory repo, MSMQ orders +2. https://github.com/bradygaster/IncomingOrderProcessor — Windows Service monitoring MSMQ + +Target: +- ProductCatalogApp → ASP.NET Core/.NET 10 or Blazor on App Service. WCF→REST API, MSMQ→Service Bus +- IncomingOrderProcessor → Azure Functions with Service Bus trigger +- Shared models → .NET 10 class library +- Infrastructure: Bicep for App Service, Function App, Service Bus +- CI/CD: GitHub Actions +- Local dev: docker-compose or Aspire + +Preserve all business logic. SOAP→REST with same data structures, MSMQ→Service Bus compatible format. + +Team: web app migration, WCF-to-API, Windows Service-to-Functions, shared models, Azure infrastructure, CI/CD, tester. Start with migration plan. +``` + +**What it demonstrates:** +- Realistic enterprise migration from legacy .NET Framework to modern Azure +- Agents analyze unfamiliar code and translate to Azure-native patterns +- Business logic preservation while modernizing infrastructure (WCF→REST, MSMQ→Service Bus) + +--- + +### 11. Multiplayer Space Trading Game + +``` +Build multiplayer space trading game (browser-based): +- Galaxy: 50+ procedural star systems with stations, trade routes +- Economy: dynamic commodity prices (fuel, ore, food, tech, luxuries) driven by supply/demand +- Ships: 3 tiers with cargo capacity, fuel range, hull strength +- Trading: buy low, sell high. Prices shift with player activity and events +- Combat: turn-based encounters with pirates/players +- Multiplayer: WebSocket real-time. Players see each other, chat, PvP opt-in +- Persistence: PostgreSQL (credits, cargo, location, ship) +- Frontend: Canvas galaxy map, HTML/CSS panels for station/trading/inventory + +Tech: Node.js, PostgreSQL, WebSocket, vanilla HTML/CSS/Canvas. + +One agent per system: economy/trading, galaxy generator/map, combat, multiplayer/networking, frontend UI, tester. Economy and galaxy work simultaneously — agree on star system data format early. Go. +``` + +**What it demonstrates:** +- Complex game with 6+ agents owning distinct but interoperating systems +- Data format decisions shared early and respected across all agents +- Economy and galaxy agents work in parallel from turn 1 + +--- + +### 12. AI Recipe App with Image Recognition + +``` +Build recipe app with image recognition (React Native Expo, Python FastAPI, SQLite): +- Camera: photograph ingredients +- Image analysis: GPT-4 Vision to identify ingredients +- Recipe matching: match against database (50+ recipes) +- Recipe display: ingredients (have vs. need), instructions, time +- Favorites: save, rate, notes +- Shopping list: auto-generate missing ingredients +- Dietary filters: vegetarian, vegan, gluten-free, dairy-free + +One agent: React Native frontend. One: FastAPI backend + DB. One: vision/AI integration. One: recipe curation/seed data. Tester: API tests with mocked vision responses. Set up team. +``` + +**What it demonstrates:** +- Cross-platform mobile + backend + AI integration in one project +- Recipe curator and AI integration agent work simultaneously with shared taxonomy +- Tester mocks vision API responses for deterministic testing before real integration + +--- + +### 13. DevOps Pipeline Builder + +``` +Build self-service DevOps platform (React, Go, PostgreSQL, Docker): +- Pipeline designer: drag-and-drop UI composing stages (build, test, deploy, notify) +- Stage templates: npm build, Docker build, Helm deploy, Slack notify +- Pipeline execution: stages run as Docker containers (Go orchestration) +- Live logs: stream to browser via SSE +- Pipeline-as-code: export/import YAML (GitHub Actions compatible) +- Secrets management: encrypted storage +- Execution history: searchable logs with status, duration, artifacts + +Team: frontend (drag-and-drop), backend (execution engine), Docker/infrastructure, security (secrets), tester. Set up team. +``` + +**What it demonstrates:** +- Agents with diverse expertise (UI, containers, cryptography) on one product +- Execution engine and pipeline designer build in parallel with shared data model +- Security agent works independently on secrets encryption + +--- + +### 14. Roguelike Dungeon Crawler + +``` +Build browser-based roguelike dungeon crawler: +- Dungeons: procedural rooms/corridors (BSP or cellular automata), 10 floors, scaling difficulty +- Character: warrior/mage/rogue with unique abilities (3 each), health/mana/stamina +- Combat: turn-based, grid-positioned. Enemy AI flanks, retreats at low HP +- Items: weapons, armor, potions, scrolls. Random loot tables. Unidentified items until used +- Fog of war: tile-based visibility with raycasting +- Rendering: Canvas with tilemap (16x16 or 32x32 colored squares) +- Permadeath: high score table with name, class, floor, cause of death +- Save: save-on-exit only (LocalStorage) + +One agent per: dungeon gen, combat + AI, items + loot, rendering + fog of war, tester. All build simultaneously with shared tile/entity data model. Start building. +``` + +**What it demonstrates:** +- Four independently buildable systems converging on shared data model +- Early data model decision via decisions.md enables full parallelism +- Tester validates game math from specs while systems are under construction + +--- + +### 15. Real-Time Collaborative Whiteboard + +``` +Build real-time collaborative whiteboard using React Flow (React + TypeScript, Node.js, WebSocket): +- Built on React Flow (https://reactflow.dev/) +- Shapes: rectangles, circles, text, sticky notes, arrows/edges +- Drag-and-drop from palette, reposition, resize (handles) +- Color picker, stroke width, fill/background per shape +- Multi-select (bounding box), group operations +- Real-time sync: cursor + edits via WebSocket +- Rooms: shareable URL +- Undo/redo per user +- Export: PNG and SVG +- Persistence: PostgreSQL (nodes, edges, viewport), auto-save every 30s + +Frontend agent: React Flow + drag-and-drop. Networking: WebSocket sync + conflict resolution. Backend: rooms + persistence. Tester: Playwright multi-user drag-and-drop tests. Set up team. +``` + +**What it demonstrates:** +- Networking and frontend agents coordinate closely on React Flow data model +- Frontend leverages React Flow's built-in features while networking syncs across users +- Tester writes multi-context Playwright tests for real-time sync validation + +--- + +### 16. Multiplayer Dice Roller — Bar Games PWA + +``` +Build mobile-first PWA dice roller (React + TypeScript, Three.js/React Three Fiber, Node.js + WebSocket, PostgreSQL): +- Mobile-first responsive, PWA installable, works offline +- Double-tap to roll: realistic 3D dice with physics (Three.js) +- Customizable: 1-10 dice, die types (d6, d10, d12, d20), colors +- Multiplayer: rooms with 6-digit code or QR, real-time roll sync, chat +- Game modes: Freeroll, Yahtzee (auto-scoring), Liar's Dice, custom rules +- Score history: roll log, replay animations, export JSON +- Sound effects, haptic feedback, night mode + +One agent: 3D dice/physics. One: PWA/gesture handling. One: multiplayer backend (rooms, WebSocket, scores). One: game logic. Tester: mobile Playwright for touch + multiplayer. Set up team. +``` + +**What it demonstrates:** +- Mobile-first project with agents specialized by concern (3D, touch, networking, logic) +- 3D and gesture agents coordinate on tap-to-roll triggers and animation states +- PWA requirements and mobile testing showcase production mobile app concerns + +--- + +## Advanced Features + +For detailed guidance on advanced features like export/import, GitHub Issues integration, ceremonies, PRD mode, human team members, and skills, see [Tips and Tricks](tips-and-tricks.md). + diff --git a/docs/scenarios/aspire-dashboard.md b/docs/src/content/docs/scenarios/aspire-dashboard.md similarity index 93% rename from docs/scenarios/aspire-dashboard.md rename to docs/src/content/docs/scenarios/aspire-dashboard.md index bbee1ec78..c7879e897 100644 --- a/docs/scenarios/aspire-dashboard.md +++ b/docs/src/content/docs/scenarios/aspire-dashboard.md @@ -2,6 +2,7 @@ > ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. +> 📌 **Squad CLI only** — The Aspire dashboard integration requires the Squad CLI (`squad aspire`). It is not available when using GitHub Copilot CLI directly. Only Squad CLI commands emit OpenTelemetry data to the dashboard. **Try this:** ``` @@ -156,6 +157,17 @@ You'll see gauges, counters, and histograms: - `squad.response.ttft` — time to first token (ms) - `squad.response.duration` — total response duration (ms) +### Rework Rate Metrics (5th DORA) + +PR rework rate instruments, exported alongside the core metrics above: + +| Instrument | Type | Unit | Description | +|-----------|------|------|-------------| +| `squad.rework.rate` | Gauge | % | Current rework rate percentage | +| `squad.rework.cycles` | Histogram | — | Review cycles per PR | +| `squad.rework.rejection_rate` | Gauge | % | Percentage of PRs with changes requested | +| `squad.rework.time_ms` | Histogram | ms | Time spent in rework | + ### **Resources** Aspire groups all telemetry by service. You'll see: 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 98% rename from docs/scenarios/client-compatibility.md rename to docs/src/content/docs/scenarios/client-compatibility.md index d9d577376..104a11476 100644 --- a/docs/scenarios/client-compatibility.md +++ b/docs/src/content/docs/scenarios/client-compatibility.md @@ -1,5 +1,7 @@ # Copilot Client Compatibility Matrix +> **Quick answer:** Not sure which interface to use? See [Choose your interface](../get-started/choose-your-interface.md) for a concise decision tree and comparison. + Squad runs on multiple Copilot surfaces — each with its own agent spawning mechanism, tool set, and constraints. This document maps Squad's core capabilities across CLI, VS Code, JetBrains, and GitHub.com to help you understand what works where. ## Quick Reference @@ -267,4 +269,4 @@ This document is based on active research spikes (#32, #33, #34) conducted in Fe - [Model Selection](../features/model-selection.md) — Cost-first routing across agents - [Parallel Execution](../features/parallel-execution.md) — Background and sync patterns - [Worktrees](../features/worktrees.md) — Multi-branch isolation -- [FAQ](../guide.md#troubleshooting) — Common questions and answers +- [Troubleshooting](./troubleshooting.md) — Common questions and answers diff --git a/docs/src/content/docs/scenarios/cross-org-auth.md b/docs/src/content/docs/scenarios/cross-org-auth.md new file mode 100644 index 000000000..34d4e823d --- /dev/null +++ b/docs/src/content/docs/scenarios/cross-org-auth.md @@ -0,0 +1,257 @@ +# Cross-organization authentication + +**Try this when you have repos in multiple GitHub accounts:** +``` +I work across personal GitHub and Enterprise Managed Users +``` + +**Try this to set up multi-account auth:** +``` +Show me how to configure gh CLI for multiple GitHub accounts +``` + +You have repositories in both personal GitHub (github.com) and GitHub Enterprise Cloud with Enterprise Managed Users (EMU). The `gh` CLI and git credentials are tied to one account at a time. Squad agents hit authentication errors when working across these boundaries. + +--- + +## The problem + +GitHub Enterprise Managed Users (EMU) provisions user accounts managed by your enterprise. Usernames typically follow a pattern like `username_shortcode` (e.g., `alice_acme`). When you work across personal GitHub and EMU organizations: + +1. Your git credentials authenticate to one account at a time +2. The `gh` CLI authenticates to one account at a time +3. Squad agents inherit your authentication context +4. When an agent tries to access a repo tied to a different account, authentication fails + +**Common error messages:** + +``` +HTTP 401: Bad credentials (github.com/api/v3) +``` + +``` +gh: authentication required for https://github.com/ORGANIZATION/REPO +``` + +``` +fatal: could not read Username for 'https://github.com': terminal prompts disabled +``` + +--- + +## Solution 1: Use `gh auth switch` + +The `gh` CLI supports multiple authenticated accounts. Log in with both your personal and EMU accounts, then switch between them as needed. + +### Step 1: Log in with both accounts + +```bash +# Log in to personal GitHub +gh auth login + +# Log in to EMU account (use the EMU hostname if your org uses a separate instance) +gh auth login --hostname github.com +``` + +If your EMU organization uses a dedicated GitHub Enterprise Cloud hostname (e.g., `ghe.mycompany.com`), specify it: + +```bash +gh auth login --hostname ghe.mycompany.com +``` + +### Step 2: Check active account + +```bash +gh auth status +``` + +Output shows which account is currently active: + +``` +github.com + ✓ Logged in to github.com as alice (keyring) + ✓ Git operations for github.com configured to use https protocol. + ✓ Token: gho_**** + +ghe.mycompany.com + ✓ Logged in to ghe.mycompany.com as alice_acme (keyring) + ✓ Active account +``` + +### Step 3: Switch accounts + +```bash +gh auth switch +``` + +Select the account you need: + +``` +? What account do you want to switch to? + > alice (github.com) + alice_acme (ghe.mycompany.com) +``` + +Or switch directly: + +```bash +gh auth switch --user alice +gh auth switch --user alice_acme --hostname ghe.mycompany.com +``` + +--- + +## Solution 2: Copilot instructions + +Add account mapping to `.github/copilot-instructions.md` so Squad agents know which account to use for which repositories. + +Create or update `.github/copilot-instructions.md` in your repository: + +```markdown +# GitHub Account Context + +When working with repositories across multiple GitHub accounts, use the following mappings: + +## Personal GitHub (github.com) +- Authenticated as: alice +- Repositories: + - github.com/alice/portfolio + - github.com/alice/blog + - github.com/open-source-org/community-project + +## Enterprise Managed Users (EMU) +- Authenticated as: alice_acme (ghe.mycompany.com) +- Repositories: + - ghe.mycompany.com/engineering/api-gateway + - ghe.mycompany.com/engineering/frontend + +Before executing `gh` or `git` commands, check the repository URL and switch to the correct account with `gh auth switch --user ` if needed. +``` + +Squad agents will read this instruction and switch accounts when they detect a cross-account operation. + +**User-level instructions:** If you work across multiple repos, add the account mapping to your global Copilot instructions at `~/.github/copilot-instructions.md` (or `%USERPROFILE%\.github\copilot-instructions.md` on Windows). + +--- + +## Solution 3: Squad skill + +Capture the cross-org auth pattern as a Squad skill. When authentication fails, the skill detects the error and suggests or attempts account switching. + +Create `.squad/skills/cross-org-auth-recovery.md`: + +```markdown +# Cross-Organization Authentication Recovery + +When `gh` or `git` operations fail with authentication errors (HTTP 401, "authentication required", "Bad credentials"), detect the failure and switch to the correct GitHub account. + +## Detection + +Look for these error patterns: +- `HTTP 401: Bad credentials` +- `gh: authentication required for https://github.com` +- `fatal: could not read Username for 'https://github.com'` + +## Recovery + +1. Run `gh auth status` to see which accounts are available +2. Extract the repository's organization or hostname from the error message +3. Match the repository to the correct account (use `.github/copilot-instructions.md` if available) +4. Run `gh auth switch --user ` to switch accounts +5. Retry the failed operation + +## Example + +```bash +# Operation fails +gh pr create --repo engineering/api-gateway +# Error: gh: authentication required for https://ghe.mycompany.com/engineering/api-gateway + +# Check accounts +gh auth status +# alice (github.com) — active +# alice_acme (ghe.mycompany.com) + +# Switch to EMU account +gh auth switch --user alice_acme --hostname ghe.mycompany.com + +# Retry operation +gh pr create --repo engineering/api-gateway +# Success +``` +``` + +The Scribe or another agent can apply this skill when auth errors occur. + +--- + +## Git credential helpers + +The `gh` CLI handles GitHub API authentication, but git clone/fetch/push operations use git's credential system. Configure git to use the correct credential helper per host or organization. + +### Per-host credentials + +If your EMU organization uses a separate hostname (e.g., `ghe.mycompany.com`): + +```bash +# Configure git to use gh CLI as credential helper for both hosts +git config --global credential.https://github.com.helper "!gh auth git-credential" +git config --global credential.https://ghe.mycompany.com.helper "!gh auth git-credential" +``` + +Git will now delegate authentication to the `gh` CLI, which uses the active account from `gh auth switch`. + +### Per-organization credentials (advanced) + +If both accounts share `github.com` but belong to different organizations: + +```bash +# Use gh CLI for personal repos +git config --global credential.https://github.com/alice.helper "!gh auth git-credential" + +# Use gh CLI for EMU org repos +git config --global credential.https://github.com/ORGANIZATION.helper "!gh auth git-credential" +``` + +**Note:** This requires git 2.36+ for per-URL credential helpers. + +--- + +## Verify active account + +Before running Squad agents, check which GitHub account is active: + +```bash +gh auth status +``` + +Look for the account marked as **Active**. + +To verify git operations use the correct account: + +```bash +# Test with a repository from each org +gh repo view alice/portfolio +gh repo view engineering/api-gateway +``` + +Both should succeed without authentication errors. + +--- + +## Tips + +- **Switch before starting Squad** — run `gh auth switch` before launching a Squad session if you know which repos you'll work on +- **Error detection works both ways** — if an agent hits an auth error, check `gh auth status` and switch manually before retrying +- **Use Copilot instructions for documentation** — document account mappings in `.github/copilot-instructions.md` so Squad agents (and human teammates) know which account to use +- **Test both accounts** — verify both `gh` and `git` operations work for each account before relying on multi-account workflows +- **EMU hostname varies** — some EMU orgs use `github.com` with organization-scoped access; others use dedicated hostnames like `ghe.mycompany.com`. Check with your GitHub admin. +- **Token permissions matter** — EMU accounts may have restricted permissions. Ensure your token has `repo`, `read:org`, and `workflow` scopes. + +--- + +## See also + +- [Private repos](./private-repos) — privacy and security for Squad on enterprise repos +- [Enterprise platforms](../features/enterprise-platforms) — Azure DevOps and Microsoft Planner support +- [Troubleshooting](./troubleshooting) — common Squad issues and fixes 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/src/content/docs/scenarios/release-process.md b/docs/src/content/docs/scenarios/release-process.md new file mode 100644 index 000000000..9674a6ada --- /dev/null +++ b/docs/src/content/docs/scenarios/release-process.md @@ -0,0 +1,357 @@ +# Release Process for Squad Maintainers + +**Try this to ship a new version:** +``` +We're ready to ship v1.2.0 — run the release process: changelog, tags, and publish +``` + +**Try this to promote to production:** +``` +Merge preview to main and cut a production release +``` + +Complete step-by-step guide for Squad maintainers: three-branch model (dev/preview/main), guard workflows, PR merging, and production release procedures. + +--- + +## Table of Contents + +1. [Branch Model Overview](#branch-model-overview) +2. [Preview Build Workflow](#preview-build-workflow) +3. [Pull Request Workflow](#pull-request-workflow) +4. [Merging Back to Dev](#merging-back-to-dev) +5. [Full Release Lifecycle](#full-release-lifecycle) +6. [Branch Protection Rules](#branch-protection-rules) +7. [Troubleshooting](#troubleshooting) +8. [Sample Prompts](#sample-prompts) + +--- + +## Branch Model Overview + +| Branch | Purpose | Who Commits | Guard Active? | Files Allowed | +|--------|---------|------------|---------------|---------------| +| **dev** | Development — all work happens here | All team members | ❌ No | Everything (`.ai-team/`, team-docs, etc.) | +| **preview** | Staging/testing — validated product only | Release coordinator | ✅ Yes | Distribution files only (`.ai-team/` blocked) | +| **main** | Production — release source for `npx` | Release coordinator | ✅ Yes | Distribution files only (`.ai-team/` blocked) | + +--- + +## Preview Build Workflow + +### Step 1: Create the Preview Branch + +```bash +git checkout dev +git pull origin dev +git checkout -b preview 2>/dev/null || git checkout preview +git reset --hard dev +``` + +### Step 2: Remove Forbidden Files (Guard Enforcement) + +Remove forbidden paths: + +```bash +git rm --cached -r .ai-team/ +git rm --cached -r team-docs/ +``` + +If there are changes: + +```bash +git commit -m "chore: remove forbidden paths for preview branch" +git push -f origin preview +``` + +### Step 3: Review and Test + +Verify CI status passes and code review is complete. Push test branches off `preview` to validate the release; if guard passes, your preview branch is clean. + +--- + +## Pull Request Workflow + +### Creating a PR (Feature Work on Dev) + +```bash +git checkout -b feature/my-feature +# ... make changes ... +git add . +git commit -m "feat: my new feature" +git push -u origin feature/my-feature +gh pr create --base dev --title "feat: my new feature" --body "Description of changes" +``` + +### Reviewing a PR + +Use GitHub UI or `gh` CLI to view and review PRs. + +### Merging a PR to Dev + +```bash +gh pr merge 123 --merge --auto +git checkout dev && git pull origin dev +``` + +--- + +## Merging Back to Dev + +After a release ships from `main`, sync changes back to `dev`: + +### Step 1: Create a Sync PR + +```bash +git checkout dev +git pull origin dev +git checkout -b chore/sync-from-main +git merge main --no-ff --no-edit +``` + +### Step 2: Resolve Conflicts (if any) + +If conflicts exist: + +```bash +git status # Lists conflicted files +git add . +git commit -m "chore: resolve merge conflicts from main" +``` + +### Step 3: Push and Merge + +```bash +git push -u origin chore/sync-from-main +gh pr create --base dev --title "chore: sync from main" --body "Bring production changes back to dev" +gh pr merge --merge --auto +git checkout dev && git pull origin dev +``` + +--- + +## Full Release Lifecycle + +### Phase 1: Preparation (on `dev`) + +1. **Update CHANGELOG.md:** + +```markdown +## [0.4.0] — 2026-02-15 + +### Added +- MCP tool discovery and integration +- Plugin marketplace support + +### Changed +- VS Code support now fully compatible + +### Community +- @csharpfritz: MCP tool discovery (#11) +``` + +2. **Update version in package.json:** + +```bash +nano package.json # Set "version": "0.4.0" +``` + +3. **Commit to dev:** + +```bash +git add CHANGELOG.md package.json +git commit -m "chore: prepare release v0.4.0" +git push origin dev +``` + +### Phase 2: Preview Build (on `preview`) + +Follow [Preview Build Workflow](#preview-build-workflow). + +### Phase 3: Merge to Main (on `main`) + +1. **Create a release PR:** + +```bash +git checkout main +git pull origin main +git checkout -b release/v0.4.0 +git merge --no-ff preview -m "Release v0.4.0" +git push -u origin release/v0.4.0 +``` + +2. **Create PR for final review:** + +```bash +gh pr create --base main --title "Release v0.4.0" --body "Final release PR. Guard enforces file restrictions." +``` + +3. **Wait for guard to pass**, then merge: + +```bash +gh pr merge --merge --auto +``` + +### Phase 4: Tag the Release (on `main`) + +```bash +git checkout main +git pull origin main +git tag -a v0.4.0 -m "Release v0.4.0: MCP integration, Plugin marketplace, Notifications" +git push origin v0.4.0 +``` + +Tag format: `vX.Y.Z` (must match `package.json` version). + +### Phase 5: Verify the Release + +Monitor the release workflow: + +```bash +gh run list --workflow release.yml --status in_progress +gh run list --workflow release.yml --status completed --limit 1 +``` + +### Phase 6: Sync Back to Dev + +```bash +git checkout dev +git pull origin dev +git checkout -b chore/sync-from-main +git merge main --no-ff +git push -u origin chore/sync-from-main +gh pr merge --merge --auto +git pull origin dev +``` + +--- + +## Branch Protection Rules + +| Branch | Rule | Effect | +|--------|------|--------| +| `main` | Require PR review | All PRs require at least 1 approval | +| `main` | Require status checks to pass | Tests must pass before merge allowed | +| `preview` | Require status checks to pass | Tests must pass before merge allowed | + +--- + +## Troubleshooting + +### Issue: Forbidden Files Detected in PR + +Use `.gitignore` rules and verify `git status` before pushing: + +```bash +git status +git rm --cached -r .ai-team/ +git commit -m "chore: remove runtime state files" +git push +``` + +--- + +### Issue: SSH Hangs During Push + +**Fix:** + +```bash +# Try HTTP instead +git remote set-url origin https://github.com/bradygaster/squad.git +git push origin + +# Or test SSH +ssh -T git@github.com +``` + +--- + +### Issue: .ai-team/ Files Keep Getting Committed + +**Fix:** + +```bash +git rm --cached -r .ai-team/ +grep ".ai-team" .gitignore || echo ".ai-team/" >> .gitignore +git add .gitignore +git commit -m "chore: ensure .ai-team/ is untracked" +git push origin dev +``` + +--- + +### Issue: Missing Workflows in .github/workflows/ + +**Fix:** + +```bash +npx github:bradygaster/squad upgrade +git add .github/workflows/ +git commit -m "chore: restore Squad workflows" +git push origin dev +``` + +--- + +### Issue: GitHub Release Not Created After Tag + +**Fix:** + +```bash +gh run list --workflow release.yml --status completed --limit 1 +gh run view # Check details + +# Create manually if needed +gh release create v0.4.0 --title "v0.4.0" --notes-file CHANGELOG.md --prerelease +``` + +--- + +## Sample Prompts + +### To Prepare for Release + +``` +Kobayashi, prepare v0.4.0: update CHANGELOG.md and package.json version, commit to dev +``` + +### To Build a Preview + +``` +Kobayashi, build a preview branch from dev, remove forbidden files, push to origin, and confirm the guard passes +``` + +### To Tag a Release + +``` +Kobayashi, checkout main, create and push tag v0.4.0, verify the release workflow starts, and report when it completes +``` + +### To Sync After Release + +``` +Kobayashi, create a chore/sync-from-main branch, merge main into it, create and merge PR back to dev, and confirm dev is up to date +``` + +### To Test the Guard + +``` +Kobayashi, test the guard workflow by creating a test branch with .ai-team/ content, creating a PR to main (should fail), removing the file (should pass), and cleaning up +``` + +### To Fix a Blocked PR + +``` +Kobayashi, fetch the current PR state, remove all .ai-team/ and team-docs/ files, commit, push to update the PR, and wait for guard to pass +``` + +--- + +## Key Files Reference + +- **Release workflow:** `.github/workflows/release.yml` +- **Changelog:** `CHANGELOG.md` +- **Version:** `package.json` +- **Ignore rules:** `.gitignore`, `.npmignore` +- **Branch protection:** GitHub repo Settings → Branches + 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/src/content/docs/scenarios/troubleshooting.md b/docs/src/content/docs/scenarios/troubleshooting.md new file mode 100644 index 000000000..e7bee1c76 --- /dev/null +++ b/docs/src/content/docs/scenarios/troubleshooting.md @@ -0,0 +1,304 @@ +# Troubleshooting + +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. + +**Cause:** npm resolves `github:` package specifiers via `git+ssh://git@github.com/...`. If no SSH agent is running (or your key isn't loaded), git prompts for your passphrase on the TTY — but npm's progress spinner overwrites the prompt, making it invisible. This is an npm TTY handling issue, not a Squad bug. + +**Fix (choose one):** + +1. **Start your SSH agent first** (recommended): + ```bash + eval "$(ssh-agent -s)" + ssh-add + ``` + Then re-run `npx github:bradygaster/squad`. + +2. **Disable npm's progress spinner** to reveal the prompt: + ```bash + npx --progress=false github:bradygaster/squad + ``` + +3. **Use HTTPS instead of SSH** by configuring git: + ```bash + git config --global url."https://github.com/".insteadOf git@github.com: + ``` + +**Reference:** [#30](https://github.com/bradygaster/squad/issues/30) + +--- + +## `gh` CLI not authenticated + +**Problem:** GitHub Issues, PRs, Ralph, or Project Boards commands fail with authentication errors. + +**Cause:** The `gh` CLI isn't logged in, or is missing required scopes. + +**Fix:** + +1. Log in: + ```bash + gh auth login + ``` + +2. If using Project Boards, add the `project` scope: + ```bash + gh auth refresh -s project + ``` + +3. Verify: + ```bash + gh auth status + ``` + +--- + +## Authentication fails on cross-org repos + +**Problem:** Squad agents hit authentication errors when working with repositories across personal GitHub and GitHub Enterprise Managed Users (EMU) organizations. + +**Cause:** The `gh` CLI and git credentials are tied to one account at a time. When you switch contexts between personal and EMU repos, the active account may not have access to the target repository. + +**Fix:** + +1. Use `gh auth switch` to toggle between authenticated accounts: + ```bash + gh auth status + gh auth switch --user + ``` + +2. Add account mappings to `.github/copilot-instructions.md` so Squad agents know which account to use for which repos. + +3. Configure git credential helpers per host or organization. + +See [Cross-organization authentication](./cross-org-auth) for detailed setup instructions. + +--- + +## Node.js version too old + +**Problem:** `npx github:bradygaster/squad` fails with an engine compatibility error, or Squad behaves unexpectedly. + +**Cause:** Squad requires Node.js 20.0.0 or later (LTS), enforced via `engines` in `package.json`. + +**Fix:** + +```bash +node --version +``` + +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/) + +--- + +## Squad agent not appearing in Copilot + +**Problem:** After install, `squad` doesn't show up in the `/agent` (CLI) or `/agents` (VS Code) list in GitHub Copilot. + +**Cause:** The `.github/agents/squad.agent.md` file may not have been created, or Copilot hasn't refreshed its agent list. + +**Fix:** + +1. Verify the file exists: + ```bash + ls .github/agents/squad.agent.md + ``` + If missing, re-run `npx github:bradygaster/squad`. + +2. Restart your Copilot session — close and reopen the terminal or editor. + +--- + +## Upgrade doesn't change anything + +**Problem:** Running `npx github:bradygaster/squad upgrade` completes but nothing changes. + +**Cause:** You may already be on the latest version, or npm cached an old version. + +**Fix:** + +1. Check current version in `.github/agents/squad.agent.md` (frontmatter `version:` field). + +2. Clear npm cache and retry: + ```bash + npx --yes github:bradygaster/squad upgrade + ``` + +--- + +## `squad doctor` warnings and failures + +`squad doctor` validates your `.squad/` setup and reports each check as ✅ pass, ❌ fail, or ⚠️ warn. It always exits 0 — it's a diagnostic tool, not a gate. + +Run it any time something feels off: + +```bash +squad doctor +``` + +### Checks and how to fix them + +#### ❌ `.squad/` directory not found + +**Cause:** No squad has been initialized in this project. + +**Fix:** Run `squad init` (or `squad init --mode remote ` for dual-root setups). + +--- + +#### ❌ `config.json` — file exists but is not valid JSON + +**Cause:** The `.squad/config.json` file is corrupted or was hand-edited with a syntax error. + +**Fix:** Open `.squad/config.json` and fix the JSON syntax, or delete it and re-run `squad init`. + +--- + +#### ❌ `config.json` — teamRoot must be a string + +**Cause:** The `teamRoot` value in `.squad/config.json` is not a string (e.g., it's a number or object). + +**Fix:** Edit `.squad/config.json` so `teamRoot` is a quoted string path: + +```json +{ "teamRoot": "../my-team-repo" } +``` + +--- + +#### ⚠️ Absolute path warning — teamRoot is absolute + +**Cause:** `teamRoot` in `.squad/config.json` uses an absolute path (e.g., `/home/user/team-repo`). This works locally but breaks portability across machines. + +**Fix:** Change `teamRoot` to a relative path: + +```json +{ "teamRoot": "../my-team-repo" } +``` + +--- + +#### ❌ Team root — directory not found + +**Cause:** The `teamRoot` path in `.squad/config.json` points to a directory that doesn't exist. The team-root repo may not be cloned, or the relative path is wrong. + +**Fix:** +1. Clone the team-root repo to the expected location. +2. Or update `teamRoot` in `.squad/config.json` to the correct relative path. +3. Or re-link with `squad link `. + +--- + +#### ❌ `team.md` — file not found + +**Cause:** The `.squad/team.md` file is missing. This file defines your team roster. + +**Fix:** Run `squad init` to regenerate it, or create `.squad/team.md` manually with a `## Members` section. + +--- + +#### ⚠️ `team.md` — missing `## Members` header + +**Cause:** The file exists but doesn't contain the expected `## Members` markdown header that Squad uses to discover team members. + +**Fix:** Add a `## Members` section to `.squad/team.md`: + +```markdown +## Members + +- **Kaylee** — Engineering Lead +- **Ralph** — GitHub Operations +``` + +--- + +#### ❌ `routing.md` — file not found + +**Cause:** The `.squad/routing.md` file is missing. This file tells Squad how to route tasks to agents. + +**Fix:** Run `squad init` to regenerate it, or create `.squad/routing.md` manually. + +--- + +#### ❌ `agents/` directory — directory not found + +**Cause:** No agent definitions exist. Squad needs at least one agent directory under `.squad/agents/`. + +**Fix:** Run `squad init` to scaffold the default agents, or create `.squad/agents//` directories manually. + +--- + +#### ❌ `casting/registry.json` — file not found or invalid JSON + +**Cause:** The casting registry is missing or corrupted. This file tracks agent role assignments. + +**Fix:** Run `squad init` to regenerate it. If you need to preserve existing casting data, fix the JSON syntax in `.squad/casting/registry.json`. + +--- + +#### ❌ `decisions.md` — file not found + +**Cause:** The `.squad/decisions.md` file is missing. This file records team decisions for context continuity. + +**Fix:** Create an empty `.squad/decisions.md` file: + +```bash +touch .squad/decisions.md +``` + +--- + +### Reading the summary + +Doctor output ends with a summary line: + +``` +Summary: 7 passed, 1 failed, 1 warnings +``` + +- **All passed:** Your setup is healthy. +- **Warnings:** Non-blocking issues worth fixing (e.g., absolute paths). +- **Failures:** Missing or broken files that will affect Squad behavior. + +### Modes + +Doctor detects three setup modes automatically: + +| Mode | Trigger | Meaning | +|------|---------|---------| +| `local` | Default | Single-repo squad, everything in `.squad/` | +| `remote` | `config.json` has `teamRoot` | Dual-root setup with a separate team repo | +| `hub` | `squad-hub.json` exists in cwd | Hub layout for multi-project teams | + +--- + +## Windows-specific issues + +**Problem:** Path errors or file operations fail on Windows. + +**Cause:** Some shell commands assume Unix-style paths. + +**Fix:** Squad's core uses `path.join()` for all file operations and is Windows-safe. If you see path issues: +- Use PowerShell or Git Bash (not cmd.exe) +- Ensure git is in your PATH +- Ensure `gh` CLI is in your PATH 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 69% rename from docs/sdk-first-mode.md rename to docs/src/content/docs/sdk-first-mode.md index 040e53a42..72a22a7d2 100644 --- a/docs/sdk-first-mode.md +++ b/docs/src/content/docs/sdk-first-mode.md @@ -6,6 +6,24 @@ Squad now supports **SDK-First Mode**: define your team in TypeScript with full --- +## What gets generated + +Running `squad build` generates these files: + +| File | Condition | Contains | +|------|-----------|----------| +| `.squad/team.md` | Always | Team roster, member list, project context | +| `.squad/routing.md` | If `routing` defined | Routing rules and default agent | +| `.squad/agents/{name}/charter.md` | For each agent | Agent role, model, tools, capabilities | +| `.squad/ceremonies.md` | If `ceremonies` defined | Ceremony schedule and agenda | + +**Protected files** (never overwritten): +- `.squad/decisions.md` / `.squad/decisions-archive.md` +- `.squad/agents/*/history.md` +- `.squad/orchestration-log/*` + +--- + ## What is SDK-First Mode? In SDK-First Mode: @@ -17,18 +35,7 @@ In SDK-First Mode: This replaces manual `.squad/team.md`, `.squad/routing.md`, and agent charters with a single source of truth in code. ---- - -## Which Mode Should I Use? - -| Scenario | Command | What You Get | -|----------|---------|-------------| -| New project, want simplicity | `squad init` | Markdown-only `.squad/` directory | -| New project, want type safety | `squad init --sdk` | `.squad/` + `squad.config.ts` with typed builders | -| Existing squad, want to upgrade | `squad migrate --to sdk` | Keeps your team, generates typed config | -| SDK squad, want to simplify | `squad migrate --to markdown` | Removes config, keeps markdown | - -**Start with markdown.** It's simpler, requires no build step, and works great for most projects. **Upgrade to SDK** when you want type-safe configuration, IDE autocomplete, and the ability to define skills and ceremonies in TypeScript. +**When to use SDK mode:** For a comparison of SDK-first mode versus CLI mode, see the [Getting started guide](/guide#how-teams-form-init-mode). --- @@ -97,40 +104,15 @@ This generates: --- -## Starting a New SDK-First Project +## Start a new SDK-first project ```bash squad init --sdk ``` -This generates: -- `.squad/` directory with all standard markdown files (team.md, routing.md, agent charters, etc.) -- `squad.config.ts` at your project root using the `defineSquad()` builder syntax - -Your `squad.config.ts` is the source of truth. Edit it, then run `squad build` to regenerate `.squad/`. - -### What Gets Generated - -```typescript -import { - defineSquad, - defineTeam, - defineAgent, -} from '@bradygaster/squad-sdk'; - -export default defineSquad({ - version: '1.0.0', - team: defineTeam({ - name: 'my-project', - members: ['scribe'], - }), - agents: [ - defineAgent({ name: 'scribe', role: 'scribe', description: 'Scribe', status: 'active' }), - ], -}); -``` +This generates `.squad/` markdown files and a `squad.config.ts` at your project root using the `defineSquad()` builder syntax. Your TypeScript config is the source of truth — edit it, then run `squad build` to regenerate `.squad/`. -Without `--sdk`, `squad init` creates a markdown-only squad — no config file, no build step needed. +For the full team initialization flow, see [How teams form (Init Mode)](/guide#how-teams-form-init-mode) in the getting started guide. --- @@ -177,9 +159,37 @@ This replaces the old `squad upgrade --migrate-directory` command. --- -## Builder Functions +## Builder functions -Each builder accepts a configuration object, validates it at runtime, and returns the typed value. The pattern mirrors `defineConfig()` — identity-passthrough with runtime safety. +Each builder accepts a configuration object, validates it at runtime, and returns the typed value. + +### Common types reference + +All builders share these core patterns: + +```typescript +// Base types used across multiple builders +interface AgentCapability { + readonly name: string; + readonly level: 'expert' | 'proficient' | 'basic'; +} + +interface RoutingRule { + readonly pattern: string; + readonly agents: readonly string[]; + readonly tier?: 'direct' | 'lightweight' | 'standard' | 'full'; + readonly priority?: number; +} + +// Lifecycle and status +type AgentStatus = 'active' | 'inactive' | 'retired'; +type FallbackBehavior = 'ask' | 'default-agent' | 'coordinator'; +type OverflowStrategy = 'reject' | 'generic' | 'rotate'; +type ConfidenceLevel = 'low' | 'medium' | 'high'; +type SkillSource = 'manual' | 'observed' | 'earned' | 'extracted'; +``` + +--- ### `defineTeam(config)` @@ -194,17 +204,6 @@ const team = defineTeam({ }); ``` -**Type:** - -```typescript -interface TeamDefinition { - readonly name: string; - readonly description?: string; - readonly projectContext?: string; - readonly members: readonly string[]; -} -``` - | Field | Type | Required | Notes | |-------|------|----------|-------| | `name` | string | ✅ | Team name (non-empty) | @@ -233,25 +232,6 @@ const edie = defineAgent({ }); ``` -**Type:** - -```typescript -interface AgentDefinition { - readonly name: string; - readonly role: string; - readonly charter?: string; - readonly model?: string; - readonly tools?: readonly string[]; - readonly capabilities?: readonly AgentCapability[]; - readonly status?: 'active' | 'inactive' | 'retired'; -} - -interface AgentCapability { - readonly name: string; - readonly level: 'expert' | 'proficient' | 'basic'; -} -``` - | Field | Type | Required | Notes | |-------|------|----------|-------| | `name` | string | ✅ | Unique identifier (kebab-case, no `@`) | @@ -259,13 +239,8 @@ interface AgentCapability { | `charter` | string | ❌ | Character description or link to charter | | `model` | string | ❌ | Model preference (e.g., `"claude-sonnet-4"`, `"claude-haiku-4.5"`) | | `tools` | string[] | ❌ | Allowed tools (e.g., `["grep", "edit", "view"]`) | -| `capabilities` | object[] | ❌ | Capability list with proficiency levels | -| `status` | enum | ❌ | Lifecycle: `'active'` (default), `'inactive'`, `'retired'` | - -**Capability Levels:** -- `expert` — core competency -- `proficient` — strong knowledge -- `basic` — foundational +| `capabilities` | `AgentCapability[]` | ❌ | Capability list with proficiency levels (see Common Types) | +| `status` | `AgentStatus` | ❌ | Lifecycle: `'active'` (default), `'inactive'`, `'retired'` | --- @@ -285,33 +260,13 @@ const routing = defineRouting({ }); ``` -**Type:** - -```typescript -interface RoutingDefinition { - readonly rules: readonly RoutingRule[]; - readonly defaultAgent?: string; - readonly fallback?: 'ask' | 'default-agent' | 'coordinator'; -} - -interface RoutingRule { - readonly pattern: string; - readonly agents: readonly string[]; - readonly tier?: 'direct' | 'lightweight' | 'standard' | 'full'; - readonly priority?: number; -} -``` - -**Routing Tiers:** -- `direct` — skip ceremony, execute immediately -- `lightweight` — quick handoff, minimal overhead -- `standard` — normal workflow with decision checkpoints -- `full` — maximum governance, review gates +| Field | Type | Required | Notes | +|-------|------|----------|-------| +| `rules` | `RoutingRule[]` | ✅ | Pattern-based routing rules (see Common Types) | +| `defaultAgent` | string | ❌ | Fallback agent ref | +| `fallback` | `FallbackBehavior` | ❌ | `'ask'`, `'default-agent'`, or `'coordinator'` | -**Fallback Behavior:** -- `ask` — ask the user for routing direction -- `default-agent` — use the `defaultAgent` -- `coordinator` — delegate to the Squad coordinator +**Routing tiers:** `direct` (skip ceremony), `lightweight` (quick handoff), `standard` (normal workflow), `full` (maximum governance). --- @@ -329,19 +284,6 @@ const standup = defineCeremony({ }); ``` -**Type:** - -```typescript -interface CeremonyDefinition { - readonly name: string; - readonly trigger?: string; - readonly schedule?: string; - readonly participants?: readonly string[]; - readonly agenda?: string; - readonly hooks?: readonly string[]; -} -``` - | Field | Type | Required | Notes | |-------|------|----------|-------| | `name` | string | ✅ | Ceremony name | @@ -367,18 +309,6 @@ const hooks = defineHooks({ }); ``` -**Type:** - -```typescript -interface HooksDefinition { - readonly allowedWritePaths?: readonly string[]; - readonly blockedCommands?: readonly string[]; - readonly maxAskUser?: number; - readonly scrubPii?: boolean; - readonly reviewerLockout?: boolean; -} -``` - | Field | Type | Required | Notes | |-------|------|----------|-------| | `allowedWritePaths` | string[] | ❌ | Glob patterns (e.g., `["src/**", "docs/**"]`) | @@ -404,20 +334,11 @@ const casting = defineCasting({ }); ``` -**Type:** - -```typescript -interface CastingDefinition { - readonly allowlistUniverses?: readonly string[]; - readonly overflowStrategy?: 'reject' | 'generic' | 'rotate'; - readonly capacity?: Readonly>; -} -``` - -**Overflow Strategies:** -- `reject` — refuse to cast if universe is at capacity -- `generic` — use a generic persona -- `rotate` — cycle through available universes +| Field | Type | Required | Notes | +|-------|------|----------|-------| +| `allowlistUniverses` | string[] | ❌ | Permitted fictional universes | +| `overflowStrategy` | `OverflowStrategy` | ❌ | `'reject'`, `'generic'`, or `'rotate'` | +| `capacity` | `Record` | ❌ | Max agents per universe | --- @@ -435,18 +356,6 @@ const telemetry = defineTelemetry({ }); ``` -**Type:** - -```typescript -interface TelemetryDefinition { - readonly enabled?: boolean; - readonly endpoint?: string; - readonly serviceName?: string; - readonly sampleRate?: number; - readonly aspireDefaults?: boolean; -} -``` - | Field | Type | Required | Notes | |-------|------|----------|-------| | `enabled` | boolean | ❌ | Master on/off switch (default: `false`) | @@ -481,13 +390,13 @@ const gitWorkflow = defineSkill({ | Field | Type | Required | Description | |-------|------|----------|-------------| -| `name` | `string` | ✅ | Unique skill name (kebab-case) | -| `description` | `string` | ✅ | What this skill teaches | -| `domain` | `string` | ✅ | Category (e.g., 'orchestration', 'testing') | -| `confidence` | `'low' \| 'medium' \| 'high'` | — | Skill maturity level | -| `source` | `'manual' \| 'observed' \| 'earned' \| 'extracted'` | — | How the skill was learned | -| `content` | `string` | ✅ | The skill body (patterns, examples) | -| `tools` | `SkillTool[]` | — | MCP tools relevant to this skill | +| `name` | string | ✅ | Unique skill name (kebab-case) | +| `description` | string | ✅ | What this skill teaches | +| `domain` | string | ✅ | Category (e.g., 'orchestration', 'testing') | +| `confidence` | `ConfidenceLevel` | ❌ | `'low'`, `'medium'`, or `'high'` | +| `source` | `SkillSource` | ❌ | `'manual'`, `'observed'`, `'earned'`, or `'extracted'` | +| `content` | string | ✅ | The skill body (patterns, examples) | +| `tools` | `SkillTool[]` | ❌ | MCP tools relevant to this skill | Skills defined in `squad.config.ts` are generated to `.squad/skills/{name}/SKILL.md` when you run `squad build`. @@ -513,34 +422,19 @@ export default defineSquad({ }); ``` -**Type:** - -```typescript -interface SquadSDKConfig { - readonly version?: string; - readonly team: TeamDefinition; - readonly agents: readonly AgentDefinition[]; - readonly routing?: RoutingDefinition; - readonly ceremonies?: readonly CeremonyDefinition[]; - readonly hooks?: HooksDefinition; - readonly casting?: CastingDefinition; - readonly telemetry?: TelemetryDefinition; -} -``` - --- -## `squad build` Command +## `squad build` command Compile TypeScript Squad definitions into `.squad/` markdown. -### Usage +**Usage:** ```bash squad build [options] ``` -### Flags +**Flags:** | Flag | What it does | |------|-------------| @@ -548,65 +442,22 @@ squad build [options] | `--dry-run` | Show what would be generated without writing | | `--watch` | Rebuild on `.ts` file changes (coming soon) | -### Examples - -**Rebuild all generated files:** +**Examples:** ```bash +# Rebuild all generated files squad build -``` -**Validate that generated files match disk:** - -```bash +# Validate that generated files match disk (useful in CI/CD) squad build --check -``` -This is useful in CI/CD to ensure the config is in sync: - -```yaml -# .github/workflows/squad-check.yml -- name: Check Squad config - run: squad build --check -``` - -**Preview changes before writing:** - -```bash +# Preview changes before writing squad build --dry-run ``` -Output: -``` -ℹ️ Dry run — would generate 6 file(s): - - create .squad/team.md - create .squad/routing.md - create .squad/agents/edie/charter.md - create .squad/agents/mcmanus/charter.md - create .squad/ceremonies.md - overwrite .squad/hooks.md -``` - -### Generated Files - -`squad build` generates: - -| File | Condition | Contains | -|------|-----------|----------| -| `.squad/team.md` | Always | Team roster, member list, project context | -| `.squad/routing.md` | If `routing` defined | Routing rules and default agent | -| `.squad/agents/{name}/charter.md` | For each agent | Agent role, model, tools, capabilities | -| `.squad/ceremonies.md` | If `ceremonies` defined | Ceremony schedule and agenda | - -**Protected files** — never overwritten: -- `.squad/decisions.md` / `.squad/decisions-archive.md` -- `.squad/agents/*/history.md` -- `.squad/orchestration-log/*` - --- -## Config Discovery +## Config discovery `squad build` discovers your config in this order: @@ -614,18 +465,13 @@ Output: 2. `squad.config.ts` — Alternative location 3. `squad.config.js` — JavaScript fallback -The config must export one of: -- **`export default config`** — default export -- **`export { config }`** — named export -- **`export { squadConfig }`** — alias +The config must export: `export default config` (default export), `export { config }` (named export), or `export { squadConfig }` (alias). --- ## Validation -All builders perform runtime validation with typed error messages. - -If validation fails: +All builders perform runtime validation with typed error messages. Example: ```typescript defineAgent({ @@ -635,27 +481,6 @@ defineAgent({ // BuilderValidationError: [defineAgent] "role" must be a non-empty string ``` -Validation is: -- **Runtime** — catches errors at build time, not runtime -- **Typed** — assertions narrow TypeScript types -- **Descriptive** — error messages include field path and expected type -- **No dependencies** — no Zod, JSON Schema, or external validators - ---- - -## Migration Guide: From Manual to SDK-First - -### Before (manual `.squad/team.md`) - -```markdown -# Squad Team — Core Squad - -## Members - -| Name | Role | Charter | -|------|------|---------| -| Edie | TypeScript Engineer | `.squad/agents/edie/charter.md` | -``` You manually maintain this file and agent charters. @@ -832,5 +657,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 74% rename from docs/tips-and-tricks.md rename to docs/src/content/docs/tips-and-tricks.md index 9eea3e5ec..d375d33e0 100644 --- a/docs/tips-and-tricks.md +++ b/docs/src/content/docs/tips-and-tricks.md @@ -207,181 +207,21 @@ This prevents "we decided different things" surprises. ## Tips for Working with Ralph (Work Monitor) -### 1. Activate Ralph When You Have Backlog +Ralph excels at grinding through backlogs while you focus on urgent work. Activate him when you have open issues, let him report every 3-5 rounds, and check his status before wrapping up. The heartbeat workflow means your squad triages issues between sessions. -Ralph is most useful when you have open issues. +**Best tip:** Give Ralph scope constraints if you need to pause certain work (e.g., `"Ralph, scope: just issues"` when you don't want PRs merged yet). -``` -> Ralph, start monitoring -``` - -Ralph will: -- Check GitHub Issues for untriaged work -- Ask the Lead to triage -- Assign issues to team members -- Spawn agents to work through them -- Report every 3 rounds - -### 2. Give Ralph a Scope If Needed - -By default, Ralph monitors issues, PRs, and CI. - -``` -> Ralph, scope: just issues -``` - -Useful when: -- You're in the middle of a PR and don't want Ralph to merge it yet -- You only care about triaging issues, not closing them -- You want to focus on one type of work - -### 3. Ralph Reports Automatically Every 3-5 Rounds - -Don't ask for status — Ralph tells you. - -``` -🔄 Ralph: Round 3 complete. - ✅ 2 issues closed, 1 PR merged - 📋 3 items remaining: #42, #45, PR #12 - Continuing... (say "Ralph, idle" to stop) -``` - -When you see this, you can: -- Let Ralph keep working (he will) -- Say "Ralph, idle" to stop -- Jump in with a different task -- Check a specific issue - -### 4. Use Ralph Between Sessions - -The `squad-heartbeat` workflow runs every 30 minutes (or on your schedule). - -Ralph will: -- Triage new issues -- Assign them to team members -- Trigger `@copilot` if you have the coding agent enabled - -This means your squad works even when you're not at the keyboard. - -### 5. Check Ralph's Status Before Wrapping Up - -``` -> Ralph, status -``` - -Ralph does one check and reports: - -``` -📊 Board Status: - 🔴 Untriaged: 0 issues need triage - 🟡 In Progress: 1 issue assigned, 0 draft PRs - 🟢 Ready: 0 PRs approved - ✅ Done: 7 issues closed this session -``` - -If the board is clean, you can wrap up. If there's work, start Ralph for the next session. +→ [Full Ralph guide](features/ralph.md#ralph--work-monitor) --- ## Managing Decisions and Team Memory -### 1. Set Permanent Rules Early - -The first or second session, establish conventions. - -``` -> Here are the permanent rules for this team: -> - Always use TypeScript strict mode -> - Component naming: PascalCase (never kebab-case) -> - All exports are named exports (no defaults) -> - Test coverage must be > 80% -> - PR must have at least one review before merge -``` - -These go to `decisions.md`. Every agent reads them before working. **You only have to say them once.** +Set permanent rules early so agents read them before every task — you only say them once. When agents disagree, check `decisions.md` for missing decisions. When agents make mistakes, turn the lesson into a directive (`"Never commit environment variables to git"`). Scribe handles decision merging automatically. -### 2. Use User Directives for "Never Again" Lessons +**Best tip:** Archive outdated decisions in a "Superseded" section so agents ignore them. Check agent `history.md` files when they seem lost — they might be missing context that was learned in previous sessions. -When an agent makes a mistake, turn it into a directive. - -``` -> Never use inline styles. Use CSS classes instead. -> Always validate user input on the backend, not just the frontend. -> Never commit environment variables to git. -``` - -These get stored as directives and agents follow them automatically in future sessions. - -### 3. Check decisions.md When Agents Disagree - -If Frontend does something one way and Backend does it another way, the decision is usually missing. - -``` -Agent A: "I used kebab-case for the file names" -Agent B: "I used PascalCase for the file names" - -[You check .ai-team/decisions.md] -[No decision about file naming conventions] - -> Here's the permanent rule: all component files are PascalCase. -``` - -Now it's in the shared brain. Next agent to work on components will see this. - -### 4. Archive Outdated Decisions - -When a decision no longer applies, move it to a "Superseded" section. - -You can edit `.ai-team/decisions.md` directly: - -```markdown -## Superseded Decisions - -- **File naming (v1)**: "All files kebab-case" — SUPERSEDED by PascalCase convention in v2 -- **API versioning (v1)**: "Use URL paths for versioning" — SUPERSEDED by headers-based versioning - -## Active Decisions -... -``` - -Agents know to ignore "Superseded" sections. - -### 5. Let Scribe Handle Decision Merging - -Agents write decisions to `/decisions/inbox/`, Scribe merges them into `/decisions.md`. - -You don't have to manually merge. Just ask: - -``` -> Scribe, merge pending decisions -``` - -Scribe will: -- Read all files in `/decisions/inbox/` -- Merge them into the canonical `decisions.md` -- Deduplicate overlaps -- Clean up the inbox - -This happens automatically in mature teams, but you can force it anytime. - -### 6. Personal History Files Build Over Time - -Each agent's `.ai-team/agents/{name}/history.md` grows with every session. Check it when an agent seems lost. - -``` -[Dallas's history shows] -- React expertise: hooks, context, performance patterns -- Knowledge of routing: react-router v6 -- Knows about the design system: established in session 3 -- Familiar with the component structure: 50+ components in src/components/ -``` - -If an agent keeps asking "where are the components?", their history might not have the right info. Edit it directly or remind them: - -``` -> Dallas, your last 5 sessions were all in the same component library. -> Check your history.md for the path. -``` +→ [Full memory guide](features/memory.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 89% rename from docs/whatsnew.md rename to docs/src/content/docs/whatsnew.md index 11712d39d..52155a152 100644 --- a/docs/whatsnew.md +++ b/docs/src/content/docs/whatsnew.md @@ -11,6 +11,13 @@ Full release history for Squad — from beta through the v1 TypeScript replatfor - **Version alignment** — CLI (0.8.1) and SDK (0.8.0) snapped to 0.8.2 across all packages - **Published to npm** — `@bradygaster/squad-sdk@0.8.2` and `@bradygaster/squad-cli@0.8.2` +- **Init flow improvements** — Ralph now included in the initial agent set during `squad init`; routing templates no longer reference `@copilot` by default (#337, #338, #339) +- **`--sdk` switch** — `squad init --sdk` generates typed `squad.config.ts` with `useRole()` calls (#424) +- **`--roles` opt-in** — `squad init --roles` uses the base role catalog instead of fictional universe casting (#412) +- **CastingEngine** — CLI init now uses `CastingEngine` to map recognized universes to curated character names and backstories (#417) +- **Session Recovery skill** — New skill for finding and resuming interrupted sessions via `session_store` queries (#442) +- **Model defaults updated** — Standard code → Sonnet 4.6, premium visual → Opus 4.6, code specialist → GPT-5.3-codex, GPT-5.4 added to catalog (#429) +- **Rework rate OTEL metrics** — Four new instruments (`squad.rework.rate`, `squad.rework.cycles`, `squad.rework.rejection_rate`, `squad.rework.time_ms`) for the 5th DORA metric (#415) - **Remote squad mode** (ported from @spboyer's [PR #131](https://github.com/bradygaster/squad/pull/131)): - `resolveSquadPaths()` dual-root resolver for project-local vs team identity directories (#311) - [`squad doctor` command](reference/cli.md) — 9-check setup validation with emoji output (#312) 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..6d1ee85c1 --- /dev/null +++ b/docs/src/layouts/DocsLayout.astro @@ -0,0 +1,35 @@ +--- +import BaseLayout from './BaseLayout.astro'; +import Header from '../components/Header.astro'; +import Sidebar from '../components/Sidebar.astro'; +import Footer from '../components/Footer.astro'; +import { NAV_SECTIONS } from '../navigation'; + +interface Props { + title: string; + description?: string; + currentSlug?: string; +} + +const { title, description, currentSlug } = Astro.props; + +// Derive section name from the URL path for Pagefind metadata +const sectionDir = currentSlug?.split('/')[0] || ''; +const navSection = NAV_SECTIONS.find(s => s.dir === sectionDir); +const section = navSection?.title || 'Docs'; +--- + + +
+
+ +
+
+
+ +
+
+
+
+
+ diff --git a/docs/src/navigation.ts b/docs/src/navigation.ts new file mode 100644 index 000000000..64dd7a034 --- /dev/null +++ b/docs/src/navigation.ts @@ -0,0 +1,145 @@ +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: 'Cross-Org Auth', slug: 'scenarios/cross-org-auth' }, + { 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.

+ +
+