diff --git a/.devcontainer/CHANGELOG.md b/.devcontainer/CHANGELOG.md index 3c46ccf..d753fae 100644 --- a/.devcontainer/CHANGELOG.md +++ b/.devcontainer/CHANGELOG.md @@ -1,8 +1,133 @@ # CodeForge Devcontainer Changelog -## [v1.13.0] - 2026-02-21 +## [v1.14.0] - 2026-02-24 + +### Fixed (CodeRabbit review) +- **chromaterm/install.sh** — username auto-detection now resets to empty before candidate loop, so `${USERNAME:-root}` fallback works correctly +- **biome/install.sh** — nvm.sh sourcing wrapped in `set +u` / `set -u` to prevent unbound variable abort under `set -euo pipefail` +- **setup.js** — `ccstatusline-settings.json` added to DEFAULT_PRESERVE so user customizations survive `--force` package updates +- **docs agent-system.md** — spec-writer moved from Full-Access to Read-Only agents table (matches its `permissionMode: plan` definition) +- **guard-readonly-bash.py** — docstring corrected from "Returns JSON on stdout" to "Outputs block reason to stderr" +- **git-forensics/SKILL.md** — misleading "Blame through renames" comment fixed to "Show patch history through renames" + +### Added + +#### Nuclear Workspace Scope Enforcement +- **Blacklist system** — `/workspaces/.devcontainer/` permanently blocked for ALL operations (read, write, bash). Checked before allowlist, scope check, and cwd bypass. Cannot be overridden, even from workspace root +- **Bash enforcement** — two-layer detection in `guard-workspace-scope.py`: + - Layer 1: 20+ regex patterns extract write targets (`>`, `tee`, `cp`, `mv`, `touch`, `mkdir`, `rm`, `ln`, `rsync`, `chmod`, `chown`, `dd`, `wget -O`, `curl -o`, `tar -C`, `unzip -d`, `gcc -o`, `sqlite3`). System command exemption only when ALL targets resolve to system paths + - Layer 2: regex scans entire command for any `/workspaces/` path string — catches inline scripts, variable assignments, quoted paths. No exemptions, always runs +- **CWD context injector** (`inject-workspace-cwd.py`) — fires on SessionStart, UserPromptSubmit, PreToolUse, SubagentStart to reinforce working directory scope +- **Fail-closed error handling** — JSON parse errors, exceptions, and unknown tools now exit 2 (block) instead of exit 0 (allow) + +#### Agent System Enhancements +- **`task-completed-check.py`** — quality gate hook (TaskCompleted) runs test suite before allowing task completion +- **`teammate-idle-check.py`** — quality gate hook (TeammateIdle) prevents teammates from going idle with incomplete tasks +- **`skills/debug/SKILL.md`** — structured log investigation skill replacing the old `/debug` slash command +- **`permissionMode`** declared on all 17 agent definitions (plan for read-only, default for write-capable) +- **Agent-system README** — full plugin documentation with hook lifecycle, agent table, quality gates + +#### Skill Engine Enhancements +- **6 new skill matchers** in `skill-suggester.py`: `spec-check`, `spec-init`, `spec-new`, `spec-refine`, `spec-update`, `team` +- **Team skill expanded** (v0.2.0) — quality gate hooks, plan approval workflow, keyboard shortcuts, use case examples, best practices, limitations +- **Skill-engine README** — full plugin documentation + +#### New Features +- **chromaterm** — terminal output colorizer via ChromaTerm2 YAML rules +- **kitty-terminfo** — xterm-kitty terminfo for Kitty terminal compatibility + +#### Documentation Site +- **Astro/Starlight docs** (`docs/`) — full documentation portal with getting-started guides, plugin reference (12 pages), feature docs, customization, and API reference +- **GitHub Actions** — `deploy-docs.yml` (docs deployment), `publish-features.yml` (GHCR feature publishing), `release.yml` (release workflow) +- **Logos** — CodeForgeLogo.png, CodeForgeLogoTr.png, github-avatar.png + +#### Plugin Installation Documentation +- **Remote install instructions** added to all 11 plugin READMEs — "From GitHub" section with clone + enabledPlugins setup from `https://github.com/AnExiledDev/CodeForge` +- **GHCR feature paths** — features README updated with `ghcr.io/anexileddev/codeforge/:` and devcontainer.json usage examples +- **READMEs added** to session-context, skill-engine, spec-workflow plugins +- **Install sections added** to workspace-scope-guard, codeforge-lsp, dangerous-command-blocker, protected-files-guard, notify-hook, ticket-workflow + +#### Other +- **Marketplace metadata** — `marketplace.json` restructured with `metadata` object, `pluginRoot`, and `keywords` arrays for all plugins +- **Port forwarding** for Claude Dashboard (port 7847) in devcontainer.json +- **ChromaTerm wrapper** in setup-aliases.sh — `cc`/`claude`/`ccw` aliases pipe through `ct` when available +- **`package.json` scripts** — added `prepublishOnly`, `docs:dev`, `docs:build`, `docs:preview` + +#### ccstatusline Config Externalization +- **Widget config extracted** from inline `jq -n` generation in `install.sh` into `config/defaults/ccstatusline-settings.json` — editable JSON file, single source of truth +- **File-manifest deployment** — two new entries deploy the config to `~/.config/ccstatusline/settings.json` (if-changed) and `/usr/local/share/ccstatusline/settings.template.json` (always) +- **`${HOME}` variable expansion** added to `setup-config.sh` — enables manifest entries targeting user home directory paths + +#### Development Rules +- **CLAUDE.md** (project root) — added changelog and documentation update rules: all changes must have a changelog entry and update relevant docs + +### Changed + +#### ccstatusline Feature +- `install.sh` simplified — removed ~90 lines of inline JSON config generation, validation, and template creation. Config deployment now handled by file-manifest system + +#### Workspace Scope Guard +- Reads (Read, Glob, Grep) now **hard-blocked** outside scope — upgraded from warning (exit 0) to block (exit 2) +- Allowlist trimmed to `/workspaces/.claude/` and `/tmp/` only — removed `/workspaces/.devcontainer/`, `/workspaces/.tmp/`, `/home/vscode/` +- Hook timeout increased from 5s to 10s +- Matcher expanded to include Bash tool + +#### Hook Output Schema Migration +- All hooks migrated to `hookSpecificOutput` wrapper with explicit `hookEventName` +- `commit-reminder.py` — upgraded from advisory to blocking (`decision: block`) +- `spec-reminder.py` — upgraded from advisory to blocking (`decision: block`) +- `advisory-test-runner.py` — test failures now block with `decision: block`; passes/timeouts use `systemMessage` +- `ticket-linker.py` — output wrapped in `hookSpecificOutput` +- `git-state-injector.py`, `todo-harvester.py` — output wrapped in `hookSpecificOutput` + +#### Ticket Workflow +- Migrated from slash commands to skill-based approach — 4 slash commands and system-prompt.md replaced by skills directory -Claude Code is an idiot sandwich and ignored my instructions and workspace scope because it's a god damned idiot. +#### Skill Definitions +- All 21+ SKILL.md files rewritten with USE WHEN / DO NOT USE guidance, action-oriented descriptions, bumped to v0.2.0 +- `skill-suggester.py` keyword maps overhauled with natural phrases and concrete identifiers +- Skill suggestion output changed to mandatory directive format +- SubagentStart hook removed — suggestions now fire on UserPromptSubmit only + +#### Error Output +- `block-dangerous.py` — errors now written to stderr (was JSON on stdout) +- `guard-protected.py`, `guard-protected-bash.py` — errors now written to stderr + +#### Features +- `ccstatusline` — compact 3-line layout (was 8-line), `rawValue: true` on token widgets +- `claude-session-dashboard` — default port 3000 → 7847, `--host 0.0.0.0` for external access +- `ccms` — build cache moved from `.devcontainer/.build-cache/` to `${TMPDIR:-/tmp}/ccms-build-cache` + +#### Configuration +- `CLAUDE.md` (devcontainer) — condensed from ~308 to ~90 lines, removed redundant sections +- `spec-workflow.md` rule — condensed, defers to system prompt `` section +- `main-system-prompt.md` — expanded Agent Teams guidance: file ownership, task sizing, quality gate hooks, plan approval +- Plugin `plugin.json` files — `version` field removed across all plugins + +### Fixed +- Stale references to deleted features (mcp-reasoner, splitrail, claude-code) removed from docs +- Documentation counts updated (features: 21, agents: 17, skills: 34) +- Version mismatch in README.md corrected +- Auto-formatter/auto-linter references consolidated to auto-code-quality throughout +- Code-directive plugin references updated to agent-system, skill-engine, spec-workflow +- Personal project paths removed from .gitignore and .npmignore +- setup.js stale feature references fixed (Reasoner MCP, Go → Rust) +- `.secrets` added to .npmignore for npm publish safety +- Duplicate "### Fixed" header in v1.5.3 changelog entry +- NVM sourcing added to biome install script +- Cleanup trap added to shellcheck install script + +### Removed +- **`auto-formatter` plugin** — deleted entirely (consolidated into auto-code-quality) +- **`auto-linter` plugin** — deleted entirely (consolidated into auto-code-quality) +- **`/debug` slash command** from agent-system (replaced by debug skill) +- **4 ticket-workflow slash commands** (`ticket:new`, `ticket:work`, `ticket:review-commit`, `ticket:create-pr`) and `system-prompt.md` (replaced by skills) +- **Optional features docs** for mcp-reasoner and splitrail (features no longer exist) +- **SubagentStart hook** from skill-engine (suggestion now UserPromptSubmit only) + +--- + +## [v1.13.0] - 2026-02-21 ### Fixed @@ -488,8 +613,6 @@ Claude Code is an idiot sandwich and ignored my instructions and workspace scope - **ccstatusline powerline glyphs**: Powerline separators/caps were empty strings, rendering as underscores. Now uses proper Nerd Font glyphs (U+E0B0, U+E0B4, U+E0B6) - **Unicode rendering in external terminals**: tmux rendered ALL Unicode as underscores because `docker exec` doesn't propagate locale vars. External terminal scripts now pass `LANG`/`LC_ALL=en_US.UTF-8` and use `tmux -u` to force UTF-8 mode. Locale exports also added to `.bashrc`/`.zshrc` as permanent fallback -### Fixed - - **cc/claude aliases**: Converted from shell functions to simple aliases — functions were not reliably invoked across shell contexts (tmux, docker exec, external terminals), causing Claude to launch without config - **CLAUDE_CONFIG_DIR export**: Now exported in `.bashrc`/`.zshrc` directly, so credentials are found in all shells (not just VS Code terminals where `remoteEnv` applies) diff --git a/.devcontainer/CLAUDE.md b/.devcontainer/CLAUDE.md index 0483a5b..dcfa5f1 100644 --- a/.devcontainer/CLAUDE.md +++ b/.devcontainer/CLAUDE.md @@ -5,308 +5,93 @@ CodeForge devcontainer for AI-assisted development with Claude Code. ## Directory Structure ``` -/workspaces/ -├── .devcontainer/ # Container configuration (this directory) -│ ├── devcontainer.json # Main container definition -│ ├── .env # Environment variables -│ ├── config/ # Default configurations -│ │ ├── file-manifest.json # Declarative file-copy manifest -│ │ └── defaults/ # Files copied per manifest -│ │ ├── settings.json # Claude Code settings -│ │ ├── keybindings.json # Claude Code keybindings -│ │ ├── main-system-prompt.md -│ │ └── writing-system-prompt.md -│ ├── features/ # Custom devcontainer features -│ ├── plugins/ # Local plugin marketplace -│ │ └── devs-marketplace/ -│ └── scripts/ # Setup scripts -├── .claude/ # Runtime Claude config (created on first run) -│ ├── settings.json # Active settings (managed by file-manifest.json) -│ ├── keybindings.json # Active keybindings -│ └── main-system-prompt.md # Active system prompt -└── .gh/ # GitHub CLI config (persists across rebuilds) - └── hosts.yml # Authenticated hosts +.devcontainer/ +├── devcontainer.json # Container definition +├── .env # Setup flags (SETUP_CONFIG, SETUP_ALIASES, etc.) +├── config/ +│ ├── file-manifest.json # Declarative config file deployment +│ └── defaults/ # Source files deployed on start via file-manifest +│ ├── settings.json # Model, permissions, plugins, env vars +│ ├── main-system-prompt.md +│ ├── ccstatusline-settings.json # Status bar widget layout +│ └── rules/ # Deployed to .claude/rules/ +├── features/ # Custom devcontainer features +├── plugins/devs-marketplace/ # Local plugin marketplace +└── scripts/ # Setup scripts (run via postStartCommand) ``` -## Key Configuration Files +## Key Configuration | File | Purpose | |------|---------| -| `devcontainer.json` | Container definition: base image, features, mounts, environment | -| `.env` | Environment variables controlling setup behavior | -| `config/file-manifest.json` | Declarative manifest controlling which config files are copied and how | -| `config/defaults/settings.json` | Claude Code defaults: model, tokens, permissions, plugins | -| `config/defaults/keybindings.json` | Claude Code keybindings (empty by default — customizable) | -| `config/defaults/main-system-prompt.md` | Default system prompt defining assistant behavior | -| `config/defaults/writing-system-prompt.md` | Creative-writing system prompt used by `ccw` alias | +| `config/defaults/settings.json` | Model, tokens, permissions, plugins, env vars | +| `config/defaults/main-system-prompt.md` | System prompt defining assistant behavior | +| `config/defaults/ccstatusline-settings.json` | Status bar widget layout (deployed to ~/.config/ccstatusline/) | +| `config/file-manifest.json` | Controls which config files deploy and when | +| `devcontainer.json` | Container definition: image, features, mounts | +| `.env` | Boolean flags controlling setup steps | -> **Note**: Config file copying is controlled by `config/file-manifest.json`. Each entry specifies `overwrite`: `"if-changed"` (default, sha256-based), `"always"`, or `"never"`. Persistent changes go in `.devcontainer/config/defaults/settings.json`. +Config files deploy via `file-manifest.json` on every container start. Most deploy to `/workspaces/.claude/`; ccstatusline config deploys to `~/.config/ccstatusline/`. Each entry supports `overwrite`: `"if-changed"` (default, sha256), `"always"`, or `"never"`. Supported variables: `${CLAUDE_CONFIG_DIR}`, `${WORKSPACE_ROOT}`, `${HOME}`. ## Commands | Command | Purpose | |---------|---------| -| `claude` | Run Claude Code with auto-configuration (prefers native binary at `~/.local/bin/claude`) | -| `cc` | Shorthand for `claude` with config | -| `ccraw` | Vanilla Claude Code without any config (bypasses function override) | -| `ccw` | Claude Code with the writing system prompt — uses `writing-system-prompt.md` instead of `main-system-prompt.md`, optimized for creative and technical writing tasks | -| `ccusage` | Analyze token usage history | -| `ccburn` | Real-time token burn rate visualization | -| `agent-browser` | Headless Chromium for browser automation (Playwright-based) | -| `gh` | GitHub CLI for repo operations | -| `uv` | Fast Python package manager | -| `ast-grep` | Structural code search | -| `ccms` | Search Claude Code session history (project-scoped) | -| `cc-tools` | List all installed tools with version info | +| `cc` / `claude` | Run Claude Code with auto-configuration | +| `ccraw` | Vanilla Claude Code (bypasses config) | +| `ccw` | Claude Code with writing system prompt | +| `ccms` | Search session history (project-scoped) | +| `ccusage` / `ccburn` | Token usage analysis / burn rate | +| `agent-browser` | Headless Chromium (Playwright-based) | | `check-setup` | Verify CodeForge setup health | -| `claude-dashboard` | Local session analytics dashboard (web UI on port 3000) | +| `claude-dashboard` | Session analytics dashboard (port 7847) | +| `cc-tools` | List all installed tools with versions | + +## Plugins + +Declared in `settings.json` under `enabledPlugins`, auto-activated on start: + +- **agent-system** — 17 custom agents + built-in agent redirection +- **skill-engine** — 21 general coding skills + auto-suggestion +- **spec-workflow** — 8 spec lifecycle skills + spec-reminder hook +- **session-context** — Git state injection, TODO harvesting, commit reminders +- **auto-code-quality** — Auto-format + auto-lint + advisory test runner +- **workspace-scope-guard** — Blocks writes outside working directory +- **dangerous-command-blocker** — Blocks destructive bash commands +- **protected-files-guard** — Blocks edits to secrets/lock files +- **codeforge-lsp** — LSP for Python + TypeScript/JavaScript +- **ticket-workflow** — EARS ticket workflow + auto-linking +- **notify-hook** — Desktop notifications on completion +- **frontend-design** (Anthropic official) — UI/frontend design skill -## Feature Development - -Custom features live in `./features/`. Each feature follows the [devcontainer feature spec](https://containers.dev/implementors/features/): - -``` -features/ -└── my-feature/ - ├── devcontainer-feature.json # Metadata and options - ├── install.sh # Installation script - └── README.md # Documentation -``` - -To test a feature locally, reference it in `devcontainer.json`: -```json -"features": { - "./features/my-feature": {} -} -``` - -> **Note**: Claude Code is installed via `ghcr.io/anthropics/devcontainer-features/claude-code:1` (Anthropic's official feature). - -### Disabling Features with `version: "none"` - -Every local feature supports `"version": "none"` to skip installation entirely. This is useful for trimming build time or disabling tools you don't need without removing them from `devcontainer.json`. - -```json -"features": { - "./features/ruff": { "version": "none" }, - "./features/biome": {}, - "./features/hadolint": { "version": "none" } -} -``` - -When `version` is set to `"none"`, the feature's `install.sh` exits immediately with a skip message. The feature entry stays in `devcontainer.json` so re-enabling is a one-word change. - -**Currently disabled features** (not needed for Python/JS/TS workflow): - -| Feature | Handles | Reason | -|---------|---------|--------| -| `shfmt` | Shell formatting | Not needed — Python/JS/TS only | -| `shellcheck` | Shell linting | Not needed — Python/JS/TS only | -| `hadolint` | Dockerfile linting | Not needed — Python/JS/TS only | -| `dprint` | Markdown/YAML/TOML/Dockerfile formatting | Not needed — Python/JS/TS only | - -The auto-formatter and auto-linter plugins gracefully skip missing tools at runtime. - -**All local features support this pattern:** -ast-grep, biome, ccms, ccstatusline, claude-monitor, claude-session-dashboard, dprint, hadolint, lsp-servers, mcp-qdrant, mcp-reasoner, notify-hook, ruff, shfmt, shellcheck, splitrail, tmux - -**External features with `version: "none"` support:** -`ghcr.io/devcontainers/features/node`, `ghcr.io/devcontainers/features/github-cli`, `ghcr.io/devcontainers/features/docker-outside-of-docker`, `ghcr.io/devcontainers/features/go` (all official Microsoft features) - -**External features without `version: "none"` support:** -`ghcr.io/devcontainers-extra/features/uv`, `ghcr.io/anthropics/devcontainer-features/claude-code`, `ghcr.io/rails/devcontainer/features/bun` - -**External features with `version: "none"` support (Rust):** -`ghcr.io/devcontainers/features/rust` (official Microsoft feature) - -> **Convention**: Every new local feature must include a `version` option (default `"latest"`) in its `devcontainer-feature.json` and a skip guard at the top of `install.sh`: -> ```bash -> if [ "${VERSION}" = "none" ]; then -> echo "[feature-name] Skipping installation (version=none)" -> exit 0 -> fi -> ``` - -## Setup Scripts - -Scripts in `./scripts/` run via `postStartCommand`: - -| Script | Purpose | -|--------|---------| -| `setup.sh` | Main orchestrator | -| `setup-config.sh` | Copies config files per `config/file-manifest.json` to destinations | -| `setup-aliases.sh` | Creates `cc`/`claude`/`ccraw`/`ccw` shell aliases (prefers native binary at `~/.local/bin/claude` via `_CLAUDE_BIN`) | -| `setup-plugins.sh` | Registers local marketplace + installs official Anthropic plugins | -| `setup-update-claude.sh` | Installs native Claude Code binary on first run; background auto-updates on subsequent starts | -| `setup-terminal.sh` | Configures VS Code Shift+Enter keybinding for Claude Code multi-line input | -| `setup-projects.sh` | Auto-detects projects for VS Code Project Manager | -| `setup-auth.sh` | Configures Git and NPM auth from `.secrets` file or environment variables | -| `check-setup.sh` | Verifies CodeForge setup health (binary paths, config files, features) | -| `setup-symlink-claude.sh` | Symlinks ~/.claude for third-party tool compatibility | - -### External Terminal - -`connect-external-terminal.sh` connects to the running devcontainer from an external terminal with tmux support for Claude Code Agent Teams split-pane workflows. Run from the host: -```bash -.devcontainer/connect-external-terminal.sh -``` - -On Windows, use `connect-external-terminal.ps1` (PowerShell equivalent). - -## Installed Plugins - -Plugins are declared in `config/defaults/settings.json` under `enabledPlugins` and auto-activated on container start: - -### Official (Anthropic) -- `frontend-design@claude-plugins-official` — UI/frontend design skill - -### Local Marketplace (devs-marketplace) -- `codeforge-lsp@devs-marketplace` — LSP for Python + TypeScript/JavaScript -- `ticket-workflow@devs-marketplace` — EARS-based ticket workflow with GitHub integration and auto-linking hook -- `notify-hook@devs-marketplace` — Desktop notifications on completion -- `dangerous-command-blocker@devs-marketplace` — Blocks destructive bash commands -- `protected-files-guard@devs-marketplace` — Blocks edits to secrets/lock files -- `agent-system@devs-marketplace` — 17 custom agents with built-in agent redirection, CWD injection, and read-only bash enforcement -- `skill-engine@devs-marketplace` — 21 coding skills with auto-suggestion hook -- `spec-workflow@devs-marketplace` — 8 spec lifecycle skills with spec-reminder hook -- `session-context@devs-marketplace` — Session boundary hooks (git state injection, TODO harvesting, commit reminders) -- `auto-code-quality@devs-marketplace` — Combined auto-format + auto-lint + advisory test runner -- `workspace-scope-guard@devs-marketplace` — Blocks writes and warns on reads outside the working directory - -### Local Marketplace - -The `devs-marketplace` in `plugins/` provides locally-managed plugins: - -``` -plugins/devs-marketplace/ -├── .claude-plugin/ -│ └── marketplace.json # Marketplace manifest -└── plugins/ - ├── codeforge-lsp/ # Combined LSP plugin - ├── ticket-workflow/ # EARS ticket workflow + auto-linking hook - ├── agent-system/ # 17 custom agents + redirection - ├── skill-engine/ # 21 coding skills + auto-suggestion - ├── spec-workflow/ # 8 spec lifecycle skills - ├── session-context/ # Session boundary hooks - ├── auto-code-quality/ # Combined format + lint + test runner - ├── workspace-scope-guard/ # Workspace scope enforcement - └── ... -``` - -## Agents & Skills - -Agents and skills are distributed across focused plugins: - -**Agents** (`plugins/devs-marketplace/plugins/agent-system/agents/`): -architect, bash-exec, claude-guide, debug-logs, dependency-analyst, doc-writer, explorer, generalist, git-archaeologist, migrator, perf-profiler, refactorer, researcher, security-auditor, spec-writer, statusline-config, test-writer - -The `redirect-builtin-agents.py` hook (PreToolUse/Task) transparently swaps built-in agent types to these custom agents (e.g., Explore→explorer, Plan→architect). - -**General Skills** (`plugins/devs-marketplace/plugins/skill-engine/skills/`): -api-design, ast-grep-patterns, claude-agent-sdk, claude-code-headless, debugging, dependency-management, docker, docker-py, documentation-patterns, fastapi, git-forensics, migration-patterns, performance-profiling, pydantic-ai, refactoring-patterns, security-checklist, skill-building, sqlite, svelte5, team, testing - -**Spec Skills** (`plugins/devs-marketplace/plugins/spec-workflow/skills/`): -spec-build, spec-check, spec-init, spec-new, spec-refine, spec-review, spec-update, specification-writing - -## VS Code Keybinding Conflicts - -Claude Code runs inside VS Code's integrated terminal. VS Code intercepts some shortcuts before they reach the terminal: +## Rules System -| Shortcut | VS Code Action | Claude Code Action | -|----------|---------------|-------------------| -| `Ctrl+G` | Go to Line | `chat:externalEditor` | -| `Ctrl+S` | Save File | `chat:stash` | -| `Ctrl+T` | Open Symbol | `app:toggleTodos` | -| `Ctrl+O` | Open File | `app:toggleTranscript` | -| `Ctrl+B` | Toggle Sidebar | `task:background` | -| `Ctrl+P` | Quick Open | `chat:modelPicker` | -| `Ctrl+R` | Open Recent | `history:search` | +Rules in `config/defaults/rules/` deploy to `.claude/rules/` on every container start. They load into ALL sessions automatically. -`Ctrl+P` and `Ctrl+F` are configured to pass through to the terminal via `terminal.integrated.commandsToSkipShell` in `devcontainer.json`. For other conflicts, use Meta (Alt) variants or customize via `config/defaults/keybindings.json`. +**Current rules:** `spec-workflow.md`, `workspace-scope.md`, `session-search.md` -## Environment Variables +**Adding rules:** Create `.md` in `config/defaults/rules/`, add a manifest entry in `file-manifest.json`. -Key environment variables set in the container: +## Environment | Variable | Value | |----------|-------| -| `WORKSPACE_ROOT` | `/workspaces` | | `CLAUDE_CONFIG_DIR` | `/workspaces/.claude` | -| `GH_CONFIG_DIR` | `/workspaces/.gh` | | `ANTHROPIC_MODEL` | `claude-opus-4-6` | -| `TMPDIR` | `/workspaces/.tmp` | -| `CLAUDECODE` | `null` (unset) | - -Setting `"CLAUDECODE": null` in `remoteEnv` unsets this variable inside the container, which allows nested Claude Code sessions (claude-in-claude) that would otherwise be blocked by the outer session's detection flag. - -All setup steps are controlled by boolean flags in `.devcontainer/.env`. Set any to `false` to disable: -`SETUP_CONFIG`, `SETUP_ALIASES`, `SETUP_AUTH`, `SETUP_PLUGINS`, `SETUP_UPDATE_CLAUDE`, `SETUP_TERMINAL`, `SETUP_PROJECTS`, `SETUP_POSTSTART`. - -### Experimental Environment Variables - -These are set in `config/defaults/settings.json` under `env` and control Claude Code experimental features: - -| Variable | Value | Description | -|----------|-------|-------------| -| `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` | `1` | Enables Agent Teams (multi-agent orchestration) | -| `CLAUDE_CODE_EFFORT_LEVEL` | `high` | Sets reasoning effort level | -| `CLAUDE_CODE_ENABLE_TASKS` | `true` | Enables the task/todo system | -| `CLAUDE_CODE_PLAN_MODE_INTERVIEW_PHASE` | `true` | Enables interview phase before plan execution | -| `CLAUDE_CODE_PLAN_V2_AGENT_COUNT` | `3` | Number of agents in Plan V2 orchestration | -| `CLAUDE_CODE_PLAN_MODE_REQUIRED` | `true` | Forces plan mode for teammate agents | -| `ENABLE_CLAUDE_CODE_SM_COMPACT` | `1` | Enables smart compaction for context management | -| `CLAUDE_CODE_FORCE_GLOBAL_CACHE` | `1` | Forces global prompt caching | -| `FORCE_AUTOUPDATE_PLUGINS` | `1` | Auto-updates plugins on every session start | - -## Git Worktrees - -CodeForge supports git worktrees for working on multiple branches simultaneously. - -### Layout - -Worktrees live in a `.worktrees/` directory alongside the main repo: - -``` -/workspaces/projects/ -├── CodeForge/ # main repo (.git directory) -└── .worktrees/ # worktree container - ├── feature-a/ # worktree checkout (.git file) - └── bugfix-b/ # worktree checkout (.git file) -``` - -### Creating Compatible Worktrees - -```bash -cd /workspaces/projects/CodeForge -mkdir -p /workspaces/projects/.worktrees -git worktree add /workspaces/projects/.worktrees/my-branch my-branch -``` - -### Project Detection - -- `setup-projects.sh` scans `.worktrees/` directories at depth 3 (inside container dirs like `projects/`) -- Worktrees are detected by their `.git` file (containing `gitdir:`) and tagged with both `"git"` and `"worktree"` in Project Manager -- Each worktree appears as an independent project in VS Code Project Manager - -### Compatibility +| `WORKSPACE_ROOT` | `/workspaces` | -- `workspace-scope-guard` resolves worktree paths correctly via `os.path.realpath()` -- `protected-files-guard` protects both `.git/` directories and `.git` files (worktree pointers) -- Read-only agents (e.g., git-archaeologist) can use `git worktree list` but cannot add/remove worktrees +All experimental feature flags are in `settings.json` under `env`. Setup steps controlled by boolean flags in `.env`. ## Modifying Behavior -1. **Change default model**: Edit `config/defaults/settings.json`, update `"model"` field +1. **Change model**: Edit `config/defaults/settings.json` → `"model"` field 2. **Change system prompt**: Edit `config/defaults/main-system-prompt.md` -3. **Change keybindings**: Edit `config/defaults/keybindings.json` -4. **Add a custom config file**: Add an entry to `config/file-manifest.json` with `src`, `dest`, and optional `overwrite`/`destFilename` -5. **Add features**: Add to `"features"` in `devcontainer.json` -6. **Disable auto-setup**: Set variables to `false` in `.env` - -## Rules System - -Rules live in `config/defaults/rules/` and are copied to `.claude/rules/` by the file manifest (`config/file-manifest.json`) on every container start. Unlike CLAUDE.md (which loads on demand when entering a project), rules load automatically on every Claude Code session. +3. **Add config file**: Add entry to `config/file-manifest.json` +4. **Add features**: Add to `"features"` in `devcontainer.json` +5. **Disable features**: Set `"version": "none"` in the feature's config +6. **Disable setup steps**: Set flags to `false` in `.env` +7. **Customize status bar**: Edit `config/defaults/ccstatusline-settings.json` -**Current rules**: `spec-workflow.md`, `workspace-scope.md`, `session-search.md` +## Features -**Adding custom rules**: Create a `.md` file in `config/defaults/rules/`, then add a manifest entry in `config/file-manifest.json` pointing to `${CLAUDE_CONFIG_DIR}/rules` as the destination. The rule will be deployed on the next container start. +Custom features in `./features/` follow the [devcontainer feature spec](https://containers.dev/implementors/features/). Every local feature supports `"version": "none"` to skip installation. Claude Code is installed via `ghcr.io/anthropics/devcontainer-features/claude-code:1`. diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 17ba714..ff2cb9b 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -434,7 +434,7 @@ Common issues and solutions. For detailed troubleshooting, see [docs/troubleshoo **CodeForge Documentation**: - [Configuration Reference](docs/configuration-reference.md) — all env vars and config options - [Plugin System](docs/plugins.md) — plugin architecture and per-plugin docs -- [Optional Features](docs/optional-features.md) — mcp-qdrant and other optional components +- [Optional Features](docs/optional-features.md) — mcp-qdrant and other optional components, disabling features - [Keybinding Customization](docs/keybindings.md) — resolving VS Code conflicts - [Troubleshooting](docs/troubleshooting.md) — common issues and solutions diff --git a/.devcontainer/config/defaults/ccstatusline-settings.json b/.devcontainer/config/defaults/ccstatusline-settings.json new file mode 100644 index 0000000..2a60051 --- /dev/null +++ b/.devcontainer/config/defaults/ccstatusline-settings.json @@ -0,0 +1,147 @@ +{ + "version": 3, + "lines": [ + [ + { + "id": "d904cca6-ade8-41c1-a4f5-ddea30607a5e", + "type": "model", + "backgroundColor": "bgMagenta" + }, + { + "id": "1", + "type": "context-length", + "color": "cyan", + "rawValue": true + }, + { + "id": "db519d5a-80a7-4b44-8a9c-2c7d8c0a7176", + "type": "context-percentage-usable", + "backgroundColor": "bgRed", + "rawValue": true + }, + { + "id": "5", + "type": "tokens-input", + "color": "magenta", + "rawValue": true, + "merge": "no-padding" + }, + { + "id": "ac094d46-3673-4d41-84e3-dc8c5bcf639f", + "type": "tokens-output", + "backgroundColor": "bgMagenta", + "rawValue": true, + "merge": "no-padding" + }, + { + "id": "2ad12147-05fd-45fb-8336-53ba2e7df56c", + "type": "tokens-cached", + "backgroundColor": "bgBrightRed", + "rawValue": true, + "merge": "no-padding" + }, + { + "id": "9bacbdb4-2e01-45de-a0c0-ee6ec30fa3c2", + "type": "tokens-total", + "backgroundColor": "bgGreen", + "rawValue": true + } + ], + [ + { + "id": "3", + "type": "git-branch", + "color": "brightBlack" + }, + { + "id": "a529e50e-b9f3-4150-a812-937ab81545e8", + "type": "git-changes", + "backgroundColor": "bgBrightBlue" + }, + { + "id": "a9eaae3f-7f91-459c-833a-fbc9f01a09ae", + "type": "git-worktree", + "backgroundColor": "bgBrightBlue" + }, + { + "id": "7", + "type": "session-clock", + "color": "yellow", + "rawValue": true + }, + { + "id": "a4fe7f75-2f6c-49c7-88f6-ac7381142c2c", + "type": "session-cost", + "backgroundColor": "bgBrightWhite", + "rawValue": true + }, + { + "id": "90aae111-3d3f-4bb0-8336-230f322cc2e8", + "type": "block-timer", + "backgroundColor": "bgYellow", + "rawValue": true + }, + { + "id": "2cdff909-8297-44a1-83f9-ad4bf024391e", + "type": "version", + "backgroundColor": "bgRed", + "rawValue": true + } + ], + [ + { + "id": "cc-resume-session", + "type": "custom-command", + "commandPath": "/usr/local/bin/ccstatusline-session-resume", + "timeout": 500, + "preserveColors": false, + "maxWidth": 50, + "color": "cyan", + "backgroundColor": "bgBrightBlack" + }, + { + "id": "cc-cwd", + "type": "custom-command", + "commandPath": "/usr/local/bin/ccstatusline-cwd", + "timeout": 500, + "preserveColors": false, + "maxWidth": 40, + "color": "brightWhite", + "backgroundColor": "bgBrightBlack" + }, + { + "id": "ccburn-compact", + "type": "custom-command", + "commandPath": "/usr/local/bin/ccburn-statusline", + "timeout": 8000, + "preserveColors": true, + "maxWidth": 80, + "color": "green", + "backgroundColor": "bgBlack" + } + ] + ], + "flexMode": "full", + "compactThreshold": 60, + "colorLevel": 2, + "inheritSeparatorColors": false, + "globalBold": false, + "powerline": { + "enabled": true, + "separators": [ + "" + ], + "separatorInvertBackground": [ + false + ], + "startCaps": [ + "" + ], + "endCaps": [ + "" + ], + "autoAlign": false, + "theme": "monokai" + }, + "defaultPadding": " " +} diff --git a/.devcontainer/config/defaults/main-system-prompt.md b/.devcontainer/config/defaults/main-system-prompt.md index 4d28f11..56ae9be 100755 --- a/.devcontainer/config/defaults/main-system-prompt.md +++ b/.devcontainer/config/defaults/main-system-prompt.md @@ -92,7 +92,12 @@ Agent Teams: - REQUIRE custom agent types for team members. Assign the specialist whose domain matches the work: researcher for investigation, test-writer for tests, refactorer for transformations, etc. - general-purpose/generalist is a LAST RESORT for team members — only when no specialist's domain applies. - Limit to 3-5 active teammates based on complexity. -- Always clean up teams when work completes. +- Always clean up teams when work completes. One team per session — `TeamDelete` before starting a new one. +- File ownership: one agent per file to avoid merge conflicts. Agents with `isolation: worktree` (test-writer, refactorer, doc-writer, migrator) get automatic file isolation. +- Task sizing: aim for 5-6 self-contained tasks per teammate, each producing a clear deliverable. +- Wait for teammates: do not implement work assigned to teammates. Monitor via `TaskList`, steer via `SendMessage`. +- Quality gate hooks: TeammateIdle (checks incomplete tasks) and TaskCompleted (runs test suite) are wired in the agent-system plugin. +- Plan approval: with `CLAUDE_CODE_PLAN_MODE_REQUIRED: "true"`, teammates run in plan mode until you approve their plan via `plan_approval_response`. Team composition examples: - Feature build: researcher + test-writer + doc-writer diff --git a/.devcontainer/config/defaults/rules/spec-workflow.md b/.devcontainer/config/defaults/rules/spec-workflow.md index a916311..7dbd799 100644 --- a/.devcontainer/config/defaults/rules/spec-workflow.md +++ b/.devcontainer/config/defaults/rules/spec-workflow.md @@ -45,58 +45,4 @@ Acceptance criteria use three states during implementation: Phase 4 upgrades `[~]` to `[x]` after verification. `/spec-update` treats any remaining `[~]` as `[ ]` if they were never verified. -## Directory Convention - -`.specs/` at the project root. Domain-organized: - -``` -.specs/ -├── MILESTONES.md # Milestone tracker linking to feature specs -├── BACKLOG.md # Deferred items not yet scheduled -├── auth/ # Domain folder -│ ├── login-flow.md # Feature spec -│ └── oauth-providers.md # Feature spec -├── search/ # Domain folder -│ └── full-text-search.md -└── onboarding/ - └── user-signup.md -``` - -All specs live in domain subfolders. Only `MILESTONES.md` and `BACKLOG.md` -reside at the `.specs/` root. - -## Standard Template - -Every spec follows this structure: - -``` -# Feature: [Name] -**Domain:** [domain-name] -**Status:** implemented | partial | planned -**Last Updated:** YYYY-MM-DD -**Approval:** draft - -## Intent -## Acceptance Criteria -## Key Files -## Schema / Data Model (reference file paths only) -## API Endpoints (Method | Path | Description) -## Requirements (EARS format: FR-1, NFR-1) -## Dependencies -## Out of Scope -## Resolved Questions -## Implementation Notes (post-implementation only) -## Discrepancies (spec vs reality gaps) -``` - -## As-Built Workflow - -After implementing a feature: -1. Find the spec: Glob `.specs/**/*.md` -2. Set status to "implemented" or "partial" -3. Check off acceptance criteria with passing tests -4. Add Implementation Notes for any deviations -5. Update file paths if they changed -6. Update Last Updated date - -If no spec exists and the change is substantial, create one. +See the system prompt's `` section for the full template, directory structure, and as-built workflow. diff --git a/.devcontainer/config/file-manifest.json b/.devcontainer/config/file-manifest.json index 3d4301b..bed9a89 100644 --- a/.devcontainer/config/file-manifest.json +++ b/.devcontainer/config/file-manifest.json @@ -40,5 +40,19 @@ "dest": "${CLAUDE_CONFIG_DIR}", "enabled": true, "overwrite": "if-changed" + }, + { + "src": "defaults/ccstatusline-settings.json", + "dest": "${HOME}/.config/ccstatusline", + "destFilename": "settings.json", + "enabled": true, + "overwrite": "if-changed" + }, + { + "src": "defaults/ccstatusline-settings.json", + "dest": "/usr/local/share/ccstatusline", + "destFilename": "settings.template.json", + "enabled": true, + "overwrite": "always" } ] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 15526e3..beff159 100755 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -55,6 +55,8 @@ "./features/ast-grep", "./features/tree-sitter", "./features/lsp-servers", + "./features/kitty-terminfo", + "./features/chromaterm", "./features/ruff", "./features/shfmt", "./features/dprint", @@ -103,7 +105,7 @@ "./features/ccms": {}, "./features/claude-session-dashboard": { "version": "latest", - "port": "3000", + "port": "7847", "shells": "both", "username": "automatic" }, @@ -111,6 +113,11 @@ "./features/tree-sitter": {}, "./features/lsp-servers": {}, "./features/agent-browser": {}, + "./features/kitty-terminfo": {}, + "./features/chromaterm": { + "version": "latest", + "username": "automatic" + }, "./features/ruff": { "version": "latest", "username": "automatic" @@ -129,6 +136,17 @@ } }, + "forwardPorts": [7847], + "portsAttributes": { + "7847": { + "label": "Claude Dashboard", + "onAutoForward": "notify" + }, + "*": { + "onAutoForward": "silent" + } + }, + "postStartCommand": "bash ${containerWorkspaceFolder}/.devcontainer/scripts/setup.sh", "remoteUser": "vscode", diff --git a/.devcontainer/docs/optional-features.md b/.devcontainer/docs/optional-features.md index c5d0e3b..3ad790c 100644 --- a/.devcontainer/docs/optional-features.md +++ b/.devcontainer/docs/optional-features.md @@ -52,71 +52,6 @@ uvx mcp-server-qdrant --help --- -## mcp-reasoner (Enhanced Reasoning) - -Adds a reasoning MCP server that gives Claude Code access to structured thinking tools (beam search, Monte Carlo tree search, etc.). - -### Enabling - -Add to `devcontainer.json` under `"features"`: - -```json -"./features/mcp-reasoner": {} -``` - -### Options - -| Option | Default | Description | -|--------|---------|-------------| -| `version` | `latest` | Version to install. `"none"` to skip. | -| `username` | `automatic` | Container user to install for | - -### Prerequisites - -Already met by default container: Node.js LTS is pre-installed. - -### How It Works - -1. During build, clones and builds the mcp-reasoner Node.js project. -2. On container start, a post-start hook registers it as an MCP server in `settings.json`. -3. Claude Code gains access to reasoning tools: `beam_search`, `mcts`, `hypothesis_test`, etc. - -### Verification - -```bash -node ~/mcp-reasoner/dist/index.js --help -``` - ---- - -## splitrail (Terminal Splitting) - -A terminal multiplexer utility for splitting panes. Useful for Agent Teams workflows. - -### Enabling - -Add to `devcontainer.json` under `"features"`: - -```json -"./features/splitrail": {} -``` - -### Prerequisites - -Requires Rust toolchain. Add the Rust devcontainer feature first: - -```json -"ghcr.io/devcontainers/features/rust:1": {} -``` - -Then add splitrail to `overrideFeatureInstallOrder` after the Rust feature. - -### How It Works - -splitrail is a Rust-based tool that provides tmux pane management for Claude Code Agent Teams. It works alongside the tmux feature to provide split-pane terminal sessions. - ---- - ## Disabling Default Features Any feature can be disabled without removing it from `devcontainer.json` by setting `"version": "none"`: diff --git a/.devcontainer/docs/plugins.md b/.devcontainer/docs/plugins.md index a65f98b..71218cb 100644 --- a/.devcontainer/docs/plugins.md +++ b/.devcontainer/docs/plugins.md @@ -14,9 +14,11 @@ plugins/devs-marketplace/ ├── notify-hook/ # Desktop notifications ├── dangerous-command-blocker/ # Safety: block destructive commands ├── protected-files-guard/ # Safety: protect sensitive files - ├── auto-formatter/ # Batch formatter (Stop hook) - ├── auto-linter/ # Batch linter (Stop hook) - ├── code-directive/ # Agents, skills, hooks + ├── auto-code-quality/ # Batch formatter + linter + advisory test runner + ├── agent-system/ # 17 custom agents + redirection hooks + ├── skill-engine/ # 21 coding skills + auto-suggestion + ├── spec-workflow/ # 8 spec lifecycle skills + spec-reminder + ├── session-context/ # Git state, TODO harvesting, commit reminders └── workspace-scope-guard/ # Workspace scope enforcement ``` @@ -28,9 +30,11 @@ Plugins are enabled in `config/defaults/settings.json` under `enabledPlugins`: ```json "enabledPlugins": [ - "auto-formatter@devs-marketplace", - "auto-linter@devs-marketplace", - "code-directive@devs-marketplace" + "auto-code-quality@devs-marketplace", + "agent-system@devs-marketplace", + "skill-engine@devs-marketplace", + "spec-workflow@devs-marketplace", + "session-context@devs-marketplace" ] ``` @@ -109,11 +113,11 @@ The blocker runs as a PreToolUse hook on Bash commands. It checks the command ag Runs as a PreToolUse hook on Write and Edit operations. -### auto-formatter +### auto-code-quality -**Purpose**: Batch-formats all files edited during a Claude Code session. +**Purpose**: Batch-formats, lints, and runs advisory tests on files edited during a Claude Code session. -**Supported languages**: +**Supported formatters**: | Language | Formatter | |----------|-----------| | Python | Ruff | @@ -123,12 +127,6 @@ Runs as a PreToolUse hook on Write and Edit operations. | Markdown/YAML/TOML/Dockerfile | dprint | | Rust | rustfmt | -**How it works**: Runs as a Stop hook. When Claude Code stops (end of a conversation turn), it checks which files were edited, detects their language, and runs the appropriate formatter. Has a 30-second timeout. - -### auto-linter - -**Purpose**: Batch-lints all files edited during a Claude Code session. - **Supported linters**: | Language | Linter | |----------|--------| @@ -139,20 +137,37 @@ Runs as a PreToolUse hook on Write and Edit operations. | Dockerfile | hadolint | | Rust | clippy | -**How it works**: Runs as a Stop hook alongside auto-formatter. Checks edited files and runs the appropriate linter. Results are reported but don't block — they're informational. +**How it works**: Runs as a Stop hook. When Claude Code stops, it checks which files were edited, detects their language, and runs the appropriate formatter and linter. Also includes an advisory test runner that runs affected tests. Results are informational — they don't block. -### code-directive +### agent-system -**Purpose**: The main intelligence layer — custom agents, coding skills, and behavior hooks. +**Purpose**: 17 specialized agent definitions with built-in agent redirection. **Components**: -- **17 custom agents** — Specialized agent definitions for different task types (architect, test-writer, refactorer, etc.) -- **28 coding skills** — Domain-specific reference materials (FastAPI, Docker, testing patterns, spec workflow, etc.) +- **17 custom agents** — Specialized agent definitions for different task types (architect, explorer, test-writer, refactorer, security-auditor, researcher, doc-writer, etc.) - **Agent redirection hook** — Transparently swaps built-in agent types to custom agents (e.g., `Explore` → `explorer`, `Plan` → `architect`) -- **Syntax validation hook** — Validates code syntax before commits -- **Skill auto-suggestion hook** — Suggests relevant skills based on conversation context +- **CWD injection hook** — Injects current working directory into agent prompts +- **Read-only bash enforcement** — Prevents read-only agents from executing write operations + +For detailed agent documentation, see `plugins/devs-marketplace/plugins/agent-system/agents/`. + +### skill-engine + +**Purpose**: 21 domain-specific coding reference skills with auto-suggestion. + +**Skills**: fastapi, svelte5, docker, docker-py, pydantic-ai, sqlite, testing, debugging, security-checklist, refactoring-patterns, git-forensics, performance-profiling, documentation-patterns, migration-patterns, dependency-management, claude-code-headless, claude-agent-sdk, ast-grep-patterns, api-design, skill-building, team + +**How it works**: Skills are loaded on demand via the Skill tool. A PreToolUse hook auto-suggests relevant skills based on conversation context. + +For skill details, see `plugins/devs-marketplace/plugins/skill-engine/skills/`. + +### spec-workflow + +**Purpose**: 8 spec lifecycle skills with spec-reminder hook. + +**Skills**: spec-new, spec-refine, spec-build, spec-review, spec-update, spec-check, spec-init, specification-writing -For detailed agent and skill documentation, see the agent markdown files in `plugins/devs-marketplace/plugins/code-directive/agents/` and skill files in `plugins/devs-marketplace/plugins/code-directive/skills/`. +**How it works**: Provides a structured specification workflow. A Stop hook reminds users to update specs when code was modified but specs weren't. ### workspace-scope-guard diff --git a/.devcontainer/features/README.md b/.devcontainer/features/README.md index 7e060ba..776a845 100644 --- a/.devcontainer/features/README.md +++ b/.devcontainer/features/README.md @@ -24,9 +24,11 @@ This directory contains DevContainer Features for AI coding agent environments. | `ccms` | Claude Code session history search | ✅ | | `notify-hook` | Desktop notifications on Claude completion | ✅ | | `mcp-qdrant` | Qdrant vector database MCP server | ✅ (optional) | -| `claude-code` | Fallback config for Anthropic's official Claude Code feature | ✅ (config only) | +| `chromaterm` | Terminal output colorizer via ChromaTerm2 YAML rules | ✅ | +| `kitty-terminfo` | xterm-kitty terminfo for Kitty terminal compatibility | ✅ | +| `claude-session-dashboard` | Local analytics dashboard for Claude Code sessions | ✅ | -> **Note**: Claude Code itself is installed via `ghcr.io/anthropics/devcontainer-features/claude-code:1` (Anthropic's official feature). The local `claude-code/` directory provides only fallback configuration. +> **Note**: Claude Code itself is installed via `ghcr.io/anthropics/devcontainer-features/claude-code:1` (Anthropic's official feature). ## Feature Structure @@ -63,17 +65,29 @@ To test a feature locally before publishing: } ``` -### Publishing Features +### Using Features from GitHub -Features will be published to GitHub Container Registry (GHCR): +Features are published to GitHub Container Registry (GHCR) from the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: ``` -ghcr.io/yourorg/codeforge-features/feature-name:1 +ghcr.io/anexileddev/codeforge/: ``` -**Publishing workflow** (future): -- Push to main branch -- GitHub Actions builds and publishes +To use a feature in your own `devcontainer.json`: + +```json +{ + "features": { + "ghcr.io/anexileddev/codeforge/:1": { + "option1": "value1" + } + } +} +``` + +**Publishing workflow:** +- Push to main branch triggers GitHub Actions +- Actions build and publish features to GHCR - Tags create versioned releases ## Feature Guidelines @@ -123,4 +137,4 @@ Features are part of the CodeForge project. See main repository for contribution --- **Status**: Active Development -**Last Updated**: 2026-02-08 +**Last Updated**: 2026-02-23 diff --git a/.devcontainer/features/biome/install.sh b/.devcontainer/features/biome/install.sh index 6af3409..9e6a377 100755 --- a/.devcontainer/features/biome/install.sh +++ b/.devcontainer/features/biome/install.sh @@ -12,6 +12,19 @@ fi echo "[biome] Starting installation..." echo "[biome] Version: ${VERSION}" +# Source NVM if available +if [ -f /usr/local/share/nvm/nvm.sh ]; then + set +u + source /usr/local/share/nvm/nvm.sh + set -u +fi + +# Validate npm is available +if ! command -v npm &>/dev/null; then + echo "[biome] ERROR: npm not found. Ensure Node.js is installed." >&2 + exit 1 +fi + # Install Biome globally via npm if [ "${VERSION}" = "latest" ]; then npm install -g @biomejs/biome diff --git a/.devcontainer/features/ccms/install.sh b/.devcontainer/features/ccms/install.sh index 4578666..991d731 100755 --- a/.devcontainer/features/ccms/install.sh +++ b/.devcontainer/features/ccms/install.sh @@ -53,7 +53,7 @@ fi echo "[ccms] Installing for user: ${USERNAME}" # === BUILD CACHE === -CACHE_DIR="/workspaces/.devcontainer/.build-cache/bin" +CACHE_DIR="${TMPDIR:-/tmp}/ccms-build-cache" # === INSTALL === REPO_URL="https://github.com/mkusaka/ccms" diff --git a/.devcontainer/features/ccstatusline/install.sh b/.devcontainer/features/ccstatusline/install.sh index daceb4b..0d16f01 100755 --- a/.devcontainer/features/ccstatusline/install.sh +++ b/.devcontainer/features/ccstatusline/install.sh @@ -66,105 +66,16 @@ else echo "[ccstatusline] ccstatusline will be cached on first use via npx" fi -echo "[ccstatusline] Generating powerline configuration..." - -# Generate powerline configuration using jq (ANSI colors - same as module) -# 6-line layout with session resume command and ccburn burn rate tracking -CONFIG_JSON=$(jq -n '{ - version: 3, - lines: [ - [ - {id: "1", type: "context-length", color: "cyan"}, - {id: "db519d5a-80a7-4b44-8a9c-2c7d8c0a7176", type: "context-percentage-usable", backgroundColor: "bgRed"}, - {id: "d904cca6-ade8-41c1-a4f5-ddea30607a5e", type: "model", backgroundColor: "bgMagenta"} - ], - [ - {id: "5", type: "tokens-input", color: "magenta"}, - {id: "ac094d46-3673-4d41-84e3-dc8c5bcf639f", type: "tokens-output", backgroundColor: "bgMagenta"}, - {id: "2ad12147-05fd-45fb-8336-53ba2e7df56c", type: "tokens-cached", backgroundColor: "bgBrightRed"} - ], - [ - {id: "3", type: "git-branch", color: "brightBlack"}, - {id: "a529e50e-b9f3-4150-a812-937ab81545e8", type: "git-changes", backgroundColor: "bgBrightBlue"}, - {id: "a9eaae3f-7f91-459c-833a-fbc9f01a09ae", type: "git-worktree", backgroundColor: "bgBrightBlue"} - ], - [ - {id: "7", type: "session-clock", color: "yellow"}, - {id: "a4fe7f75-2f6c-49c7-88f6-ac7381142c2c", type: "session-cost", backgroundColor: "bgBrightWhite"}, - {id: "90aae111-3d3f-4bb0-8336-230f322cc2e8", type: "block-timer", backgroundColor: "bgYellow"} - ], - [ - {id: "9bacbdb4-2e01-45de-a0c0-ee6ec30fa3c2", type: "tokens-total", backgroundColor: "bgGreen"}, - {id: "2cdff909-8297-44a1-83f9-ad4bf024391e", type: "version", backgroundColor: "bgRed"} - ], - [ - {id: "cc-resume-session", type: "custom-command", commandPath: "/usr/local/bin/ccstatusline-session-resume", timeout: 500, preserveColors: false, maxWidth: 50, color: "cyan", backgroundColor: "bgBrightBlack"} - ], - [ - {id: "cc-cwd", type: "custom-command", commandPath: "/usr/local/bin/ccstatusline-cwd", timeout: 500, preserveColors: false, maxWidth: 40, color: "brightWhite", backgroundColor: "bgBrightBlack"} - ], - [ - {id: "ccburn-compact", type: "custom-command", commandPath: "/usr/local/bin/ccburn-statusline", timeout: 8000, preserveColors: true, maxWidth: 80, color: "green", backgroundColor: "bgBlack"} - ] - ], - flexMode: "full-minus-40", - compactThreshold: 60, - colorLevel: 2, - inheritSeparatorColors: false, - globalBold: false, - powerline: { - enabled: true, - separators: ["\ue0b0"], - separatorInvertBackground: [false], - startCaps: ["\ue0b6"], - endCaps: ["\ue0b4"], - autoAlign: false, - theme: "monokai" - }, - defaultPadding: " " -}') - -# Validate generated config -if ! echo "${CONFIG_JSON}" | jq empty 2>/dev/null; then - echo "[ccstatusline] ERROR: Generated configuration is invalid JSON" - exit 1 -fi - -echo "[ccstatusline] Writing configuration..." - -CONFIG_DIR="${USER_HOME}/.config/ccstatusline" -CONFIG_FILE="${CONFIG_DIR}/settings.json" - -# Create directory -mkdir -p "${CONFIG_DIR}" - -# Write config using secure temp file -TEMP_CONFIG=$(mktemp) -chmod 644 "${TEMP_CONFIG}" -echo "${CONFIG_JSON}" | jq . > "${TEMP_CONFIG}" - -# Move to final location -mv "${TEMP_CONFIG}" "${CONFIG_FILE}" - -# Set ownership -if ! chown "${USERNAME}:${USERNAME}" "${CONFIG_FILE}" 2>/dev/null; then - echo "[ccstatusline] WARNING: Could not set ownership on ${CONFIG_FILE}" - echo " Fix: sudo chown ${USERNAME}:${USERNAME} ${CONFIG_FILE}" -fi - -if ! chown "${USERNAME}:${USERNAME}" "${CONFIG_DIR}" 2>/dev/null; then - echo "[ccstatusline] WARNING: Could not set ownership on ${CONFIG_DIR}" -fi - -echo "[ccstatusline] ✓ Configuration written to ${CONFIG_FILE}" - -# Create template directory and save config template -echo "[ccstatusline] Creating configuration template..." +# Widget config is managed by file-manifest.json (deployed by setup-config.sh) +# Source: .devcontainer/config/defaults/ccstatusline-settings.json +# Deployed to: ~/.config/ccstatusline/settings.json (if-changed) +# Template: /usr/local/share/ccstatusline/settings.template.json (always) +echo "[ccstatusline] Widget config managed by file-manifest.json" + +# Create directories so wrapper doesn't fail before first post-start +mkdir -p "${USER_HOME}/.config/ccstatusline" mkdir -p /usr/local/share/ccstatusline -TEMPLATE_FILE=/usr/local/share/ccstatusline/settings.template.json -echo "${CONFIG_JSON}" | jq . > "${TEMPLATE_FILE}" -chmod 644 "${TEMPLATE_FILE}" -echo "[ccstatusline] ✓ Template saved to ${TEMPLATE_FILE}" +chown "${USERNAME}:${USERNAME}" "${USER_HOME}/.config/ccstatusline" 2>/dev/null || true # Create session resume helper script for custom-command widget # Reads Claude Code JSON from stdin, outputs the session ID @@ -321,31 +232,22 @@ echo " ccstatusline Installation Complete" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "Configuration:" -echo " • Config file: ${CONFIG_FILE}" +echo " • Source: .devcontainer/config/defaults/ccstatusline-settings.json" +echo " • Deployed to: ~/.config/ccstatusline/settings.json (by file-manifest)" +echo " • Template: /usr/local/share/ccstatusline/settings.template.json" echo " • User: ${USERNAME}" -echo " • Theme: Powerline (8 lines, 17 widgets, ANSI colors)" echo " • Protected by: /usr/local/bin/ccstatusline-wrapper" echo "" -echo "Display:" -echo " Line 1: Context Length | Context % | Model" -echo " Line 2: Tokens In | Tokens Out | Tokens Cached" -echo " Line 3: Git Branch | Git Changes | Git Worktree" -echo " Line 4: Session Clock | Session Cost | Block Timer" -echo " Line 5: Tokens Total | Version" -echo " Line 6: Session ID" -echo " Line 7: Working Directory" -echo " Line 8: Burn Rate (ccburn compact)" -echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Next Steps" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" -echo "1. Configuration will be applied automatically on container creation" +echo "1. Widget config is deployed automatically on container start" echo "" -echo "2. Test manually:" -echo " echo '{\"model\":{\"display_name\":\"Test\"}}' | npx -y ccstatusline@latest" +echo "2. To customize: edit .devcontainer/config/defaults/ccstatusline-settings.json" +echo " Changes deploy on next container start (if-changed)" echo "" -echo "3. View configuration:" -echo " cat ${CONFIG_FILE} | jq ." +echo "3. Test manually:" +echo " echo '{\"model\":{\"display_name\":\"Test\"}}' | npx -y ccstatusline@latest" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/.devcontainer/features/chromaterm/README.md b/.devcontainer/features/chromaterm/README.md new file mode 100644 index 0000000..bf6c274 --- /dev/null +++ b/.devcontainer/features/chromaterm/README.md @@ -0,0 +1,42 @@ +# chromaterm + +Terminal output colorizer using regex-based YAML rules. + +## What It Does + +Installs [ChromaTerm2](https://github.com/rgcr/ChromaTerm2) via `uv tool`. ChromaTerm2 applies regex-based color highlighting to terminal output using configurable YAML rules. + +## Options + +| Option | Default | Description | +|--------|---------|-------------| +| `version` | `latest` | ChromaTerm2 version to install. Set `"none"` to skip. | +| `username` | `automatic` | Container user to install for | + +## Usage + +```bash +# Pipe any command through ct for colorized output +some-command | ct + +# Use with a custom config +ct --config ~/.chromaterm.yml +``` + +## Configuration + +Create a `~/.chromaterm.yml` file with regex rules: + +```yaml +rules: + - regex: "ERROR|FATAL" + color: red bold + - regex: "WARNING|WARN" + color: yellow + - regex: "INFO" + color: green +``` + +## Prerequisites + +Requires `uv` (pre-installed in CodeForge container). diff --git a/.devcontainer/features/chromaterm/chromaterm.yml b/.devcontainer/features/chromaterm/chromaterm.yml new file mode 100644 index 0000000..d9a3cc3 --- /dev/null +++ b/.devcontainer/features/chromaterm/chromaterm.yml @@ -0,0 +1,35 @@ +# ChromaTerm rules — additive to built-in defaults +# Customize to taste — this file won't be overwritten on rebuild. +# +# Built-in defaults already cover: errors, warnings, success, URLs, +# IPv4/IPv6, MAC addresses, dates, times, sizes, numbers. +# See: https://github.com/rgcr/ChromaTerm2 +# +# These rules add patterns the defaults don't handle. +# Colors: f#HEX (foreground), b#HEX (background), bold, italic, underline + +palette: + file_purple: '#bd93f9' + line_gray: '#6272a4' + info_blue: '#8be9fd' + hash_yellow: '#f1fa8c' + +rules: + # File paths with optional line numbers (e.g., src/main.py:42) + # Covers common extensions for languages used in development + - description: File paths with line numbers + regex: '(?<=[\s(]|^)([a-zA-Z0-9_./-]+\.(py|ts|tsx|js|jsx|md|json|yml|yaml|toml|sh|rs|go|sql|css|html|svelte))(:(\d+))?' + color: + 1: f.file_purple underline + 4: f.line_gray + exclusive: true + + # Info/debug markers (not covered by defaults) + - description: Info and debug markers + regex: '\b(INFO|DEBUG|HINT|NOTE|TRACE|VERBOSE)\b' + color: f.info_blue + + # Git short commit hashes (7-12 hex chars) + - description: Git commit hashes + regex: '(?<=commit |merge |pick |revert |fixup )[0-9a-f]{7,40}' + color: f.hash_yellow diff --git a/.devcontainer/features/chromaterm/devcontainer-feature.json b/.devcontainer/features/chromaterm/devcontainer-feature.json new file mode 100644 index 0000000..5ca162a --- /dev/null +++ b/.devcontainer/features/chromaterm/devcontainer-feature.json @@ -0,0 +1,23 @@ +{ + "id": "chromaterm", + "version": "1.0.0", + "name": "ChromaTerm - Terminal Output Colorizer", + "description": "Installs ChromaTerm2 for regex-based CLI output colorization via YAML rules", + "maintainer": "AnExiledDev", + "documentationURL": "https://github.com/rgcr/ChromaTerm2", + "options": { + "version": { + "type": "string", + "description": "ChromaTerm2 version to install (e.g., 'latest', '2.1.0', 'none' to skip)", + "default": "latest" + }, + "username": { + "type": "string", + "description": "Container user to install for", + "default": "automatic" + } + }, + "installsAfter": [ + "ghcr.io/devcontainers-extra/features/uv" + ] +} diff --git a/.devcontainer/features/chromaterm/install.sh b/.devcontainer/features/chromaterm/install.sh new file mode 100755 index 0000000..355895a --- /dev/null +++ b/.devcontainer/features/chromaterm/install.sh @@ -0,0 +1,113 @@ +#!/bin/bash +set -euo pipefail + +# ============================== +# ChromaTerm DevContainer Feature +# Installs ChromaTerm2 via uv tool +# ============================== + +CT_VERSION="${VERSION:-latest}" +USERNAME="${USERNAME:-automatic}" + +# Skip installation if version is "none" +if [ "${CT_VERSION}" = "none" ]; then + echo "[chromaterm] Skipping installation (version=none)" + exit 0 +fi + +echo "[chromaterm] Starting ChromaTerm2 installation..." + +# ---------- USER ---------- +if [[ "${USERNAME}" == "auto" || "${USERNAME}" == "automatic" ]]; then + USERNAME="" + for u in vscode node codespace; do + if id -u "$u" >/dev/null 2>&1; then + USERNAME="$u" + break + fi + done + USERNAME="${USERNAME:-root}" +fi + +USER_HOME="$(eval echo "~${USERNAME}")" + +echo "[chromaterm] Target user: ${USERNAME}" +echo "[chromaterm] Version: ${CT_VERSION}" + +fail() { + echo "[chromaterm] ERROR: $1" >&2 + exit 1 +} + +run_as_user() { + sudo -u "${USERNAME}" env \ + HOME="${USER_HOME}" \ + "$@" +} + +# ---------- UV DISCOVERY ---------- +find_uv() { + command -v uv 2>/dev/null && return 0 + for p in /usr/local/bin/uv /usr/bin/uv /opt/uv/bin/uv; do + [[ -x "$p" ]] && echo "$p" && return 0 + done + find /usr /opt -maxdepth 4 -type f -name uv -executable 2>/dev/null | head -n 1 +} + +# ---------- INSTALL ---------- +UV_BIN="$(find_uv || true)" +[[ -n "${UV_BIN}" ]] || fail "uv is not installed (devcontainer uv feature missing or broken)" + +echo "[chromaterm] Using uv at: ${UV_BIN}" + +if [[ "${CT_VERSION}" == "latest" ]]; then + run_as_user "${UV_BIN}" tool install chromaterm2 +else + run_as_user "${UV_BIN}" tool install "chromaterm2==${CT_VERSION}" +fi + +# ---------- DEPLOY DEFAULT CONFIG ---------- +CT_CONFIG="${USER_HOME}/.chromaterm.yml" +FEATURE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ ! -f "${CT_CONFIG}" ]; then + if [ -f "${FEATURE_DIR}/chromaterm.yml" ]; then + cp "${FEATURE_DIR}/chromaterm.yml" "${CT_CONFIG}" + chown "${USERNAME}:${USERNAME}" "${CT_CONFIG}" 2>/dev/null || true + echo "[chromaterm] Deployed default config to ${CT_CONFIG}" + fi +else + echo "[chromaterm] Config already exists at ${CT_CONFIG} — not overwriting" +fi + +# ---------- VERIFY ---------- +BIN_DIR="${USER_HOME}/.local/bin" + +if [ -x "${BIN_DIR}/ct" ]; then + INSTALLED_VERSION="$("${BIN_DIR}/ct" --version 2>/dev/null || echo "unknown")" + echo "[chromaterm] ✓ ChromaTerm2 installed (${INSTALLED_VERSION})" +else + echo "[chromaterm] ERROR: ct not found in ${BIN_DIR}" >&2 + ls -la "${BIN_DIR}" 2>/dev/null || true + exit 1 +fi + +# ---------- SUMMARY ---------- +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " ChromaTerm2 Installation Complete" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo "Configuration:" +echo " • User: ${USERNAME}" +echo " • Version: ${CT_VERSION}" +echo " • Config: ${CT_CONFIG}" +echo "" +echo "Usage:" +echo " ct # Wrap any command with colorization" +echo " echo 'ERROR test' | ct # Pipe output through ChromaTerm" +echo " cc / claude # Auto-wrapped when ct is installed" +echo "" +echo "Edit ~/.chromaterm.yml to customize highlighting rules." +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/.devcontainer/features/claude-session-dashboard/README.md b/.devcontainer/features/claude-session-dashboard/README.md index 1af9109..0a7a7a2 100644 --- a/.devcontainer/features/claude-session-dashboard/README.md +++ b/.devcontainer/features/claude-session-dashboard/README.md @@ -16,14 +16,14 @@ Installs [claude-session-dashboard](https://github.com/dlupiak/claude-session-da | Option | Default | Description | |--------|---------|-------------| | `version` | `latest` | npm package version (`latest`, `1.0.0`, or `none` to skip) | -| `port` | `3000` | Default port for the dashboard server | +| `port` | `7847` | Default port for the dashboard server | | `shells` | `both` | Shell configs to add alias to (`bash`, `zsh`, `both`) | | `username` | `automatic` | Container user to install for | ## Usage ```bash -# Start the dashboard (default port 3000) +# Start the dashboard (default port 7847) claude-dashboard # Start on a custom port diff --git a/.devcontainer/features/claude-session-dashboard/devcontainer-feature.json b/.devcontainer/features/claude-session-dashboard/devcontainer-feature.json index a573e38..bade8f4 100644 --- a/.devcontainer/features/claude-session-dashboard/devcontainer-feature.json +++ b/.devcontainer/features/claude-session-dashboard/devcontainer-feature.json @@ -14,7 +14,7 @@ "port": { "type": "string", "description": "Default port for the dashboard server", - "default": "3000" + "default": "7847" }, "shells": { "type": "string", diff --git a/.devcontainer/features/claude-session-dashboard/install.sh b/.devcontainer/features/claude-session-dashboard/install.sh index bab1262..0b9f43e 100755 --- a/.devcontainer/features/claude-session-dashboard/install.sh +++ b/.devcontainer/features/claude-session-dashboard/install.sh @@ -8,7 +8,7 @@ set -euo pipefail # === IMPORT OPTIONS === DASHBOARD_VERSION="${VERSION:-latest}" -PORT="${PORT:-3000}" +PORT="${PORT:-7847}" SHELLS="${SHELLS:-both}" USERNAME="${USERNAME:-automatic}" @@ -112,7 +112,7 @@ chmod +x "${HOOK_SCRIPT}" echo "[claude-session-dashboard] Created poststart hook for settings persistence" # === SHELL ALIASES === -ALIAS_CMD="alias claude-dashboard=\"claude-dashboard --port ${PORT}\"" +ALIAS_CMD="alias claude-dashboard=\"claude-dashboard --host 0.0.0.0 --port ${PORT}\"" configure_shell() { local shell_rc="$1" diff --git a/.devcontainer/features/kitty-terminfo/README.md b/.devcontainer/features/kitty-terminfo/README.md new file mode 100644 index 0000000..fd2dde0 --- /dev/null +++ b/.devcontainer/features/kitty-terminfo/README.md @@ -0,0 +1,32 @@ +# kitty-terminfo + +Installs xterm-kitty terminfo so Kitty terminal users get full color and capability support. + +## What It Does + +Downloads and compiles the official kitty terminfo entry from the [Kitty terminal repository](https://github.com/kovidgoyal/kitty). This ensures Kitty terminal users connecting to the container get proper color rendering, cursor shapes, and terminal capabilities. + +## Options + +| Option | Default | Description | +|--------|---------|-------------| +| `version` | `latest` | Set `"none"` to skip installation. | + +## Usage + +No configuration needed. Once installed, containers automatically recognize `TERM=xterm-kitty` and provide full capability support. + +```bash +# Verify installation +infocmp xterm-kitty + +# Check color support +tput colors # should return 256 +``` + +## How It Works + +1. Checks if `xterm-kitty` terminfo is already present (skips if so) +2. Installs `ncurses-bin` if `tic` compiler is not available +3. Downloads the official kitty terminfo from GitHub +4. Compiles and installs to `/usr/share/terminfo` diff --git a/.devcontainer/features/kitty-terminfo/devcontainer-feature.json b/.devcontainer/features/kitty-terminfo/devcontainer-feature.json new file mode 100644 index 0000000..c86c5bd --- /dev/null +++ b/.devcontainer/features/kitty-terminfo/devcontainer-feature.json @@ -0,0 +1,13 @@ +{ + "id": "kitty-terminfo", + "version": "1.0.0", + "name": "Kitty Terminal Terminfo", + "description": "Installs xterm-kitty terminfo so Kitty terminal users get full color and capability support", + "options": { + "version": { + "type": "string", + "description": "'latest' to install, 'none' to skip", + "default": "latest" + } + } +} diff --git a/.devcontainer/features/kitty-terminfo/install.sh b/.devcontainer/features/kitty-terminfo/install.sh new file mode 100755 index 0000000..5741b96 --- /dev/null +++ b/.devcontainer/features/kitty-terminfo/install.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -euo pipefail + +# ============================== +# Kitty Terminfo DevContainer Feature +# Installs xterm-kitty terminfo entry +# ============================== + +VERSION="${VERSION:-latest}" + +# Skip installation if version is "none" +if [ "${VERSION}" = "none" ]; then + echo "[kitty-terminfo] Skipping installation (version=none)" + exit 0 +fi + +echo "[kitty-terminfo] Starting xterm-kitty terminfo installation..." + +# ---------- CHECK EXISTING ---------- +if infocmp xterm-kitty >/dev/null 2>&1; then + echo "[kitty-terminfo] xterm-kitty terminfo already installed — skipping" + exit 0 +fi + +# ---------- CHECK TIC ---------- +if ! command -v tic >/dev/null 2>&1; then + echo "[kitty-terminfo] Installing ncurses-bin for tic compiler..." + apt-get update -qq && apt-get install -y -qq ncurses-bin +fi + +# ---------- DOWNLOAD ---------- +TERMINFO_URL="https://raw.githubusercontent.com/kovidgoyal/kitty/master/terminfo/kitty.terminfo" +TMPFILE="$(mktemp /tmp/kitty-terminfo.XXXXXX)" + +cleanup() { rm -f "${TMPFILE}"; } +trap cleanup EXIT + +echo "[kitty-terminfo] Downloading kitty terminfo from GitHub..." +if ! curl -fsSL "${TERMINFO_URL}" -o "${TMPFILE}"; then + echo "[kitty-terminfo] ERROR: Failed to download kitty terminfo" >&2 + exit 1 +fi + +# ---------- COMPILE ---------- +echo "[kitty-terminfo] Compiling terminfo entry..." +if ! tic -x -o /usr/share/terminfo "${TMPFILE}"; then + echo "[kitty-terminfo] ERROR: Failed to compile terminfo" >&2 + exit 1 +fi + +# ---------- VERIFY ---------- +if infocmp xterm-kitty >/dev/null 2>&1; then + echo "[kitty-terminfo] ✓ xterm-kitty terminfo installed successfully" +else + echo "[kitty-terminfo] ERROR: xterm-kitty terminfo not found after install" >&2 + exit 1 +fi + +# ---------- SUMMARY ---------- +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Kitty Terminfo Installation Complete" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo " Kitty terminal users now get full color and" +echo " capability support when connecting to this" +echo " container." +echo "" +echo " Verify: infocmp xterm-kitty" +echo " Check: tput colors (should return 256)" +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/.devcontainer/features/shellcheck/install.sh b/.devcontainer/features/shellcheck/install.sh index 4f6dfa5..39c6d86 100755 --- a/.devcontainer/features/shellcheck/install.sh +++ b/.devcontainer/features/shellcheck/install.sh @@ -16,9 +16,13 @@ fi echo "[shellcheck] Starting installation..." +cleanup() { + apt-get clean -y 2>/dev/null || true + rm -rf /var/lib/apt/lists/* +} +trap cleanup EXIT + apt-get update -y apt-get install -y --no-install-recommends shellcheck -apt-get clean -y -rm -rf /var/lib/apt/lists/* echo "[shellcheck] Installed: $(shellcheck --version 2>/dev/null | head -2 || echo 'unknown')" diff --git a/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json b/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json index ffeb9f8..2a3a824 100644 --- a/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +++ b/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json @@ -1,7 +1,11 @@ { "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "devs-marketplace", - "description": "CodeForge plugin marketplace for development tools", + "metadata": { + "description": "CodeForge plugin marketplace for development tools", + "version": "1.0.0", + "pluginRoot": "./plugins" + }, "owner": { "name": "AnExiledDev" }, @@ -10,125 +14,89 @@ "name": "codeforge-lsp", "description": "LSP servers for CodeForge (Python, TypeScript, Go)", "version": "1.0.0", - "source": "./plugins/codeforge-lsp", + "source": "codeforge-lsp", "category": "development", - "lspServers": { - "pyright": { - "command": "pyright-langserver", - "args": ["--stdio"], - "extensionToLanguage": { - ".py": "python", - ".pyi": "python" - } - }, - "typescript": { - "command": "typescript-language-server", - "args": ["--stdio"], - "extensionToLanguage": { - ".ts": "typescript", - ".tsx": "typescriptreact", - ".js": "javascript", - ".jsx": "javascriptreact", - ".mts": "typescript", - ".cts": "typescript", - ".mjs": "javascript", - ".cjs": "javascript" - } - }, - "gopls": { - "command": "gopls", - "args": ["serve"], - "extensionToLanguage": { - ".go": "go", - ".mod": "go.mod", - ".sum": "go.sum" - } - } - } + "keywords": ["lsp", "python", "typescript", "go"] }, { "name": "ticket-workflow", "description": "EARS-based ticket workflow with GitHub integration", "version": "1.0.0", - "source": "./plugins/ticket-workflow", - "category": "workflow" + "source": "ticket-workflow", + "category": "workflow", + "keywords": ["tickets", "github", "workflow", "ears", "issues", "pr"] }, { "name": "notify-hook", "description": "Desktop notifications and audio chime when Claude finishes responding", "version": "1.0.0", - "source": "./plugins/notify-hook", - "category": "productivity" + "source": "notify-hook", + "category": "productivity", + "keywords": ["notifications", "desktop", "audio"] }, { "name": "dangerous-command-blocker", "description": "Blocks dangerous bash commands (rm -rf, sudo rm, chmod 777, force push)", "version": "1.0.0", - "source": "./plugins/dangerous-command-blocker", - "category": "safety" + "source": "dangerous-command-blocker", + "category": "safety", + "keywords": ["safety", "bash", "blocker"] }, { "name": "protected-files-guard", "description": "Blocks modifications to .env, lock files, .git/, and credentials", "version": "1.0.0", - "source": "./plugins/protected-files-guard", - "category": "safety" - }, - { - "name": "auto-formatter", - "description": "Batch-formats edited files at Stop (Ruff for Python, gofmt for Go, Biome for JS/TS/CSS/JSON/GraphQL/HTML, shfmt for Shell, dprint for Markdown/YAML/TOML/Dockerfile, rustfmt for Rust)", - "version": "1.0.0", - "source": "./plugins/auto-formatter", - "category": "development" - }, - { - "name": "auto-linter", - "description": "Auto-lints edited files at Stop (Pyright + Ruff for Python, Biome for JS/TS/CSS/GraphQL, ShellCheck for Shell, go vet for Go, hadolint for Dockerfile, clippy for Rust)", - "version": "1.0.0", - "source": "./plugins/auto-linter", - "category": "development" + "source": "protected-files-guard", + "category": "safety", + "keywords": ["safety", "secrets", "env", "lockfiles"] }, { "name": "agent-system", "description": "17 custom agents with built-in agent redirection, CWD injection, and read-only bash enforcement", "version": "1.0.0", - "source": "./plugins/agent-system", - "category": "development" + "source": "agent-system", + "category": "development", + "keywords": ["agents", "subagents", "redirection"] }, { "name": "skill-engine", "description": "21 coding knowledge packs with auto-suggestion for frameworks, tools, and patterns", "version": "1.0.0", - "source": "./plugins/skill-engine", - "category": "development" + "source": "skill-engine", + "category": "development", + "keywords": ["skills", "knowledge", "auto-suggestion"] }, { "name": "spec-workflow", "description": "Specification lifecycle management: creation, refinement, building, reviewing, updating, and auditing", "version": "1.0.0", - "source": "./plugins/spec-workflow", - "category": "workflow" + "source": "spec-workflow", + "category": "workflow", + "keywords": ["specifications", "lifecycle", "ears"] }, { "name": "session-context", "description": "Session lifecycle hooks: git state injection, TODO harvesting, and commit reminders", "version": "1.0.0", - "source": "./plugins/session-context", - "category": "development" + "source": "session-context", + "category": "development", + "keywords": ["session", "git", "todos", "commits"] }, { "name": "auto-code-quality", "description": "Self-contained code quality: auto-format + auto-lint edited files (Ruff/Black, Biome, gofmt, shfmt, dprint, rustfmt, Pyright, ShellCheck, go vet, hadolint, clippy)", "version": "1.0.0", - "source": "./plugins/auto-code-quality", - "category": "development" + "source": "auto-code-quality", + "category": "development", + "keywords": ["formatting", "linting", "syntax", "quality"] }, { "name": "workspace-scope-guard", "description": "Enforces working directory scope — blocks writes and warns on reads outside the project", "version": "1.0.0", - "source": "./plugins/workspace-scope-guard", - "category": "safety" + "source": "workspace-scope-guard", + "category": "safety", + "keywords": ["safety", "scope", "workspace"] } ] } diff --git a/.devcontainer/plugins/devs-marketplace/.gitignore b/.devcontainer/plugins/devs-marketplace/.gitignore new file mode 100644 index 0000000..7a60b85 --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/plugin.json b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/plugin.json index fb9ce44..a686443 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/plugin.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/plugin.json @@ -1,7 +1,6 @@ { "name": "agent-system", "description": "17 custom agents with built-in agent redirection, CWD injection, and read-only bash enforcement", - "version": "1.0.0", "author": { "name": "AnExiledDev" } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/README.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/README.md new file mode 100644 index 0000000..b84617b --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/README.md @@ -0,0 +1,197 @@ +# agent-system + +Claude Code plugin that provides 17 custom specialist agents with automatic built-in agent redirection, working directory injection, read-only bash enforcement, and team quality gates. + +## What It Does + +Replaces Claude Code's built-in agents with enhanced custom agents that carry domain-specific instructions, safety hooks, and tailored tool configurations. Also provides team orchestration quality gates. + +### Custom Agents + +| Agent | Specialty | Access | +|-------|-----------|--------| +| architect | Implementation planning, trade-off analysis | Read-only | +| bash-exec | Terminal command execution | Bash only | +| claude-guide | Claude Code features, configuration, best practices | Read-only | +| debug-logs | Log investigation and issue diagnosis | Read-only | +| dependency-analyst | Outdated/vulnerable dependency analysis | Read-only | +| doc-writer | READMEs, API docs, usage guides | Full access | +| explorer | Fast codebase search and structure mapping | Read-only | +| generalist | General-purpose multi-step tasks | Full access | +| git-archaeologist | Git history, blame, branch analysis | Read-only | +| migrator | Framework/version upgrades and migrations | Full access | +| perf-profiler | Profiling, benchmarks, bottleneck identification | Read-only | +| refactorer | Safe code transformations with regression testing | Full access | +| researcher | Web research, technology investigation | Read-only | +| security-auditor | OWASP audit, secrets scan, vulnerability detection | Read-only | +| spec-writer | EARS requirements, acceptance criteria, feature specs | Read-only | +| statusline-config | Claude Code status line configuration | Full access | +| test-writer | Test suites with auto-verification | Full access | + +### Agent Redirection + +Built-in agent types are transparently redirected to their enhanced custom equivalents: + +| Built-in Type | Redirects To | +|---------------|-------------| +| Explore | explorer | +| Plan | architect | +| general-purpose | generalist | +| Bash | bash-exec | +| claude-code-guide | claude-guide | +| statusline-setup | statusline-config | + +### Quality Gates + +| Hook | Script | Purpose | +|------|--------|---------| +| TeammateIdle | `teammate-idle-check.py` | Prevents teammates from going idle with incomplete tasks | +| TaskCompleted | `task-completed-check.py` | Runs test suite before allowing task completion | + +Per-agent hooks (registered within agent definitions, not in hooks.json): + +| Agent | Hook | Script | Purpose | +|-------|------|--------|---------| +| refactorer | PostToolUse (Edit) | `verify-no-regression.py` | Runs tests after each edit to catch regressions | +| test-writer | Stop | `verify-tests-pass.py` | Verifies written tests actually pass | + +## How It Works + +### Hook Lifecycle + +``` +Claude calls the Task tool (spawning a subagent) + | + +-> PreToolUse/Task fires + | | + | +-> redirect-builtin-agents.py + | | + | +-> Built-in agent name? -> Rewrite to custom agent + | +-> Already custom? -> Pass through + | + +-> SubagentStart fires (all subagents) + | | + | +-> inject-cwd.py + | | + | +-> Injects working directory as additionalContext + | + +-> Subagent works... + | + +-> TaskCompleted fires + | | + | +-> task-completed-check.py + | | + | +-> Detect test framework -> Run tests + | +-> Tests pass? -> Allow completion + | +-> Tests fail? -> Block, send feedback + | + +-> TeammateIdle fires (team mode) + | + +-> teammate-idle-check.py + | + +-> Check task list for incomplete tasks + +-> Found? -> Send feedback to resume work +``` + +### Read-Only Bash Enforcement + +Read-only agents (explorer, researcher, architect, etc.) have their Bash access restricted by `guard-readonly-bash.py`. Blocked operations include: + +- File mutations: `rm`, `mv`, `cp`, `mkdir`, `touch`, `chmod`, `chown` +- Output redirection: `>`, `>>`, `tee` +- Command chaining with writes: pipes to destructive commands +- Eval/exec patterns + +### Exit Code Behavior + +| Script | Exit 0 | Exit 2 | +|--------|--------|--------| +| redirect-builtin-agents.py | Allow (or rewrite) | Block with error | +| inject-cwd.py | Inject context | N/A | +| guard-readonly-bash.py | Allow command | Block write operation | +| task-completed-check.py | Tests pass | Tests fail (block completion) | +| teammate-idle-check.py | No incomplete tasks | Has incomplete tasks | + +### Timeouts + +| Hook | Timeout | +|------|---------| +| Agent redirection (PreToolUse) | 5s | +| CWD injection (SubagentStart) | 3s | +| Teammate idle check | 10s | +| Task completed check | 60s | + +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "agent-system@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + +## Plugin Structure + +``` +agent-system/ ++-- .claude-plugin/ +| +-- plugin.json # Plugin metadata ++-- agents/ +| +-- architect.md # 17 agent definition files +| +-- bash-exec.md +| +-- claude-guide.md +| +-- debug-logs.md +| +-- dependency-analyst.md +| +-- doc-writer.md +| +-- explorer.md +| +-- generalist.md +| +-- git-archaeologist.md +| +-- migrator.md +| +-- perf-profiler.md +| +-- refactorer.md +| +-- researcher.md +| +-- security-auditor.md +| +-- spec-writer.md +| +-- statusline-config.md +| +-- test-writer.md ++-- hooks/ +| +-- hooks.json # Hook registrations ++-- scripts/ +| +-- guard-readonly-bash.py # Read-only bash enforcement +| +-- inject-cwd.py # Working directory injection +| +-- redirect-builtin-agents.py # Built-in agent redirection +| +-- task-completed-check.py # Test suite quality gate +| +-- teammate-idle-check.py # Incomplete task checker +| +-- verify-no-regression.py # Post-edit regression tests (refactorer) +| +-- verify-tests-pass.py # Test verification (test-writer) ++-- skills/ +| +-- debug/ +| +-- SKILL.md # Structured log investigation skill ++-- AGENT-REDIRECTION.md # Redirection mechanism docs ++-- REVIEW-RUBRIC.md # Agent/skill quality rubric ++-- README.md # This file +``` + +## Requirements + +- Python 3.11+ +- Claude Code with plugin hook support (agents, hooks, skills) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/architect.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/architect.md index 72001e8..aa2d42e 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/architect.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/architect.md @@ -7,10 +7,12 @@ description: >- "how should we architect", "what's the best strategy for", "create an implementation plan", or needs step-by-step plans, dependency analysis, risk assessment, or architectural decision-making. Returns structured - plans with critical file paths and never modifies any files. + plans with critical file paths and never modifies any files. Do not + use for implementation, code generation, or file modifications. tools: Read, Glob, Grep, Bash, WebSearch, WebFetch model: opus color: magenta +permissionMode: plan memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/bash-exec.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/bash-exec.md index 9d11a86..4b328a5 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/bash-exec.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/bash-exec.md @@ -6,9 +6,12 @@ description: >- execution, process management, or any terminal task. Follows git safety protocols, quotes paths with spaces, and reports command output clearly. Has only the Bash tool — no file reading or searching capabilities. + Do not use for file reading, code search, or tasks requiring file + content analysis. tools: Bash model: sonnet color: yellow +permissionMode: default memory: scope: project --- diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/claude-guide.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/claude-guide.md index 462e1bc..3447b14 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/claude-guide.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/claude-guide.md @@ -9,10 +9,13 @@ description: >- on Claude Code features, hooks, slash commands, skills, plugins, IDE integrations, keyboard shortcuts, Agent SDK setup, or API usage. Before spawning a new instance, check if there is already a running or recently - completed claude-guide agent that you can resume using the "resume" parameter. + completed claude-guide agent that you can resume using the "resume" + parameter. Do not use for code implementation, file modifications, or + questions unrelated to Claude Code, Agent SDK, or the Claude API. tools: Glob, Grep, Read, WebFetch, WebSearch model: haiku color: cyan +permissionMode: plan memory: scope: user skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/debug-logs.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/debug-logs.md index 3b359e3..1f1b033 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/debug-logs.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/debug-logs.md @@ -3,10 +3,15 @@ name: debug-logs description: >- Read-only agent that finds and analyzes log files across Docker containers, application frameworks, and system services to identify errors, crashes, - and performance issues. Reports structured findings with root cause assessment. + and performance issues. Reports structured findings with root cause + assessment. Do not use for fixing issues, modifying code, or + application-level debugging — log analysis and diagnosis only. tools: Bash, Read, Glob, Grep model: sonnet color: red +permissionMode: plan +memory: + scope: project skills: - debugging --- diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/dependency-analyst.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/dependency-analyst.md index f53b5eb..ee02f76 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/dependency-analyst.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/dependency-analyst.md @@ -8,10 +8,14 @@ description: >- packages", "audit dependencies", "check dependency health", "license check", "are my dependencies up to date", "npm audit", "pip audit", or needs any dependency analysis across Node.js, Python, Rust, or Go ecosystems. - Reports findings without modifying any files. + Reports findings without modifying any files. Do not use for + installing, upgrading, or modifying dependencies — analysis and + advisory reporting only. tools: Read, Bash, Glob, Grep model: haiku color: blue +permissionMode: plan +background: true memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/doc-writer.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/doc-writer.md index 3b0be33..b191210 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/doc-writer.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/doc-writer.md @@ -7,10 +7,13 @@ description: >- "write a README", "document this", "add docstrings", "add JSDoc", "update the docs", "write API documentation", "create architecture docs", "document these functions", or needs any form of code documentation, inline comments, - or technical writing. + or technical writing. Do not use for modifying source code logic, + fixing bugs, or feature implementation. tools: Read, Edit, Glob, Grep model: opus color: cyan +permissionMode: acceptEdits +isolation: worktree memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/explorer.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/explorer.md index 4d43486..cd49084 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/explorer.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/explorer.md @@ -8,10 +8,12 @@ description: >- "what files contain", or needs quick file discovery, pattern matching, or codebase navigation. Supports thoroughness levels: quick, medium, very thorough. Reports findings with absolute file paths and never - modifies any files. + modifies any files. Do not use for code modifications, multi-step + research requiring web access, or implementation tasks. tools: Read, Glob, Grep, Bash model: haiku color: blue +permissionMode: plan memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/generalist.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/generalist.md index 139bba6..3c81f69 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/generalist.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/generalist.md @@ -6,10 +6,18 @@ description: >- the user needs a keyword or file search that may require multiple attempts, multi-file investigation, code modifications across several files, or any complex task that doesn't fit a specialist agent's domain. Has access - to all tools and can both read and write files. + to all tools and can both read and write files. Do not use when a + specialist agent clearly matches the task — prefer the domain + specialist for better results. tools: "*" +disallowedTools: + - EnterPlanMode + - EnterWorktree + - TeamCreate + - TeamDelete model: inherit color: green +permissionMode: default memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/git-archaeologist.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/git-archaeologist.md index 4959ded..cb23d92 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/git-archaeologist.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/git-archaeologist.md @@ -8,9 +8,12 @@ description: >- "git blame", "git bisect", "what happened to this code", "show the history of this file", "who contributed to this module", "recover lost commit", "trace this function's evolution", or needs any git history forensics. + Do not use for modifying git history, making commits, pushing, or any + git write operations. tools: Read, Grep, Bash model: haiku color: blue +permissionMode: plan memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/migrator.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/migrator.md index bc112eb..7332f6b 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/migrator.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/migrator.md @@ -8,10 +8,13 @@ description: >- "update the framework", "bump Python version", "convert from Express to Fastify", "upgrade Pydantic", "modernize the codebase", or needs any framework, library, or language version migration with step-by-step - verification. + verification. Do not use for new feature development, bug fixes, or + changes unrelated to version or framework migration. tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch model: opus color: magenta +permissionMode: acceptEdits +isolation: worktree memory: scope: user skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/perf-profiler.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/perf-profiler.md index ff86800..c215345 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/perf-profiler.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/perf-profiler.md @@ -8,10 +8,13 @@ description: >- "measure performance", "optimize the build", "check response times", "profile the database queries", "find memory leaks", or needs any performance measurement, bottleneck identification, or optimization - guidance backed by profiling data. + guidance backed by profiling data. Do not use for implementing + optimizations or modifying code — measurement and analysis only. tools: Read, Bash, Glob, Grep model: sonnet color: yellow +permissionMode: plan +background: true memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/refactorer.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/refactorer.md index e0d0c36..26fa3b4 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/refactorer.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/refactorer.md @@ -7,10 +7,14 @@ description: >- asks "refactor this", "clean up this code", "reduce complexity", "split this class", "extract this function", "remove duplication", "simplify this module", or discusses code smells, technical debt, or structural improvements. - Runs tests after every edit to guarantee safety. + Runs tests after every edit to guarantee safety. Do not use for + adding new features, fixing bugs, or making behavioral changes to + code. tools: Read, Edit, Glob, Grep, Bash model: opus color: yellow +permissionMode: acceptEdits +isolation: worktree memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/researcher.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/researcher.md index 91b1505..6891255 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/researcher.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/researcher.md @@ -7,12 +7,16 @@ description: >- approach for", "investigate this", "research", "look into", "compare X vs Y", "explain this concept", or needs codebase analysis, library evaluation, technology comparison, or technical deep-dives. Reports structured findings - with citations without modifying any files. + with citations without modifying any files. Do not use for code + modifications, file writing, or implementation tasks. tools: Read, Glob, Grep, WebSearch, WebFetch, Bash model: sonnet color: cyan +permissionMode: plan memory: scope: user +skills: + - documentation-patterns --- # Research Agent diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/security-auditor.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/security-auditor.md index 2adfcea..a8059f7 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/security-auditor.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/security-auditor.md @@ -8,10 +8,13 @@ description: >- "find hardcoded credentials", "check dependency vulnerabilities", "OWASP review", "security check", or needs a security assessment of any code. Reports findings with severity ratings and remediation guidance without - modifying any files. + modifying any files. Do not use for fixing vulnerabilities or + implementing security changes — audit and reporting only. tools: Read, Glob, Grep, Bash model: sonnet color: red +permissionMode: plan +background: true memory: scope: user skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/spec-writer.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/spec-writer.md index ff7f4cc..fe6ba5a 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/spec-writer.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/spec-writer.md @@ -8,10 +8,12 @@ description: >- "spec this feature", "write user stories", "define the behavior of", "create a technical specification", or needs structured requirements, acceptance criteria, or feature specifications grounded in the actual - codebase state. + codebase state. Do not use for code implementation or writing + executable code — specification authoring only. tools: Read, Glob, Grep, WebSearch model: opus color: magenta +permissionMode: plan memory: scope: user skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/statusline-config.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/statusline-config.md index 9269885..3cf2a35 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/statusline-config.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/statusline-config.md @@ -5,10 +5,13 @@ description: >- status line setting. Use when the user asks "set up my status line", "convert my PS1", "customize the status bar", "show git branch in status line", "add context usage to status line", or wants to configure what appears in - Claude Code's bottom status bar. Can read shell configs and write settings. + Claude Code's bottom status bar. Can read shell configs and write + settings. Do not use for general Claude Code settings, non-status-line + configuration, or shell profile modifications. tools: Read, Edit model: sonnet color: orange +permissionMode: acceptEdits memory: scope: user --- diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/test-writer.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/test-writer.md index dcfd711..db8181d 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/test-writer.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/test-writer.md @@ -7,10 +7,13 @@ description: >- "write tests for", "add tests", "increase test coverage", "create unit tests", "add integration tests", "test this function", "test this module", or needs automated test coverage for any code. Supports pytest, Vitest, Jest, Go - testing, and Rust test frameworks. + testing, and Rust test frameworks. Do not use for modifying + application source code, fixing bugs, or implementing features. tools: Read, Write, Edit, Glob, Grep, Bash model: opus color: green +permissionMode: acceptEdits +isolation: worktree memory: scope: project skills: diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/hooks/hooks.json index 4d2e017..75f3b3b 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/hooks/hooks.json @@ -1,5 +1,5 @@ { - "description": "Agent redirection and subagent configuration hooks", + "description": "Agent redirection, subagent configuration, and team quality gate hooks", "hooks": { "PreToolUse": [ { @@ -24,6 +24,28 @@ } ] } + ], + "TeammateIdle": [ + { + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/teammate-idle-check.py", + "timeout": 10 + } + ] + } + ], + "TaskCompleted": [ + { + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/task-completed-check.py", + "timeout": 60 + } + ] + } ] } } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py index 2d4c032..d176c21 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py @@ -12,7 +12,7 @@ (>, >>), eval/exec, inline scripting (python -c, node -e), and path/backslash prefix bypasses (/usr/bin/rm, \\rm). -Reads tool input from stdin (JSON). Returns JSON on stdout. +Reads tool input from stdin (JSON). Outputs block reason to stderr. Exit 0: Command is safe (allowed) Exit 2: Command would modify state (blocked) """ @@ -601,7 +601,7 @@ def main(): error = check_general_readonly(command) if error: - json.dump({"error": error}, sys.stdout) + print(error, file=sys.stderr) sys.exit(2) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/inject-cwd.py b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/inject-cwd.py index 8c56f89..2b67e5a 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/inject-cwd.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/inject-cwd.py @@ -23,10 +23,13 @@ def main(): json.dump( { - "additionalContext": ( - f"Working Directory: {cwd} — restrict all file operations to " - f"this directory unless explicitly instructed otherwise." - ) + "hookSpecificOutput": { + "hookEventName": "SubagentStart", + "additionalContext": ( + f"Working Directory: {cwd} — restrict all file operations to " + f"this directory unless explicitly instructed otherwise." + ), + } }, sys.stdout, ) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/task-completed-check.py b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/task-completed-check.py new file mode 100644 index 0000000..1ccfd8d --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/task-completed-check.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +""" +TaskCompleted quality gate — runs project test suite before allowing completion. + +Detects the project's test framework and runs it. If tests fail, the task +stays open and the teammate receives feedback to fix the failures. + +Exit 0: Tests pass (or no test framework / runner not installed) +Exit 2: Tests fail (task stays open, feedback sent via stderr) +""" + +import json +import os +import subprocess +import sys + +TIMEOUT_SECONDS = 60 + + +def detect_test_framework(cwd: str) -> tuple[str, list[str]]: + """Detect which test framework is available in the project. + + Checks for: pytest, vitest, jest, mocha, go test, cargo test. + Falls back to npm test if a test script is defined. + + Returns: + Tuple of (framework_name, command_list) or ("", []) if none found. + """ + try: + entries = set(os.listdir(cwd)) + except OSError: + return ("", []) + + # Python: pytest + if "pytest.ini" in entries or "conftest.py" in entries: + return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"]) + + for cfg_name in ("pyproject.toml", "setup.cfg", "tox.ini"): + cfg_path = os.path.join(cwd, cfg_name) + if os.path.isfile(cfg_path): + try: + with open(cfg_path, "r", encoding="utf-8") as f: + content = f.read() + if any( + marker in content + for marker in ("[tool.pytest", "[pytest]", "[tool:pytest]") + ): + return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"]) + except OSError: + pass + + if "tests" in entries and os.path.isdir(os.path.join(cwd, "tests")): + return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"]) + + for entry in entries: + if entry.startswith("test_") and entry.endswith(".py"): + return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"]) + + # JavaScript: vitest + for name in entries: + if name.startswith("vitest.config"): + return ("vitest", ["npx", "vitest", "run", "--reporter=verbose"]) + + for vite_cfg in ("vite.config.ts", "vite.config.js"): + cfg_path = os.path.join(cwd, vite_cfg) + if os.path.isfile(cfg_path): + try: + with open(cfg_path, "r", encoding="utf-8") as f: + if "test" in f.read(): + return ( + "vitest", + ["npx", "vitest", "run", "--reporter=verbose"], + ) + except OSError: + pass + + # JavaScript: jest + for name in entries: + if name.startswith("jest.config"): + return ("jest", ["npx", "jest", "--verbose"]) + + pkg_json = os.path.join(cwd, "package.json") + if os.path.isfile(pkg_json): + try: + with open(pkg_json, "r", encoding="utf-8") as f: + pkg = json.loads(f.read()) + + if "jest" in pkg: + return ("jest", ["npx", "jest", "--verbose"]) + + dev_deps = pkg.get("devDependencies", {}) + deps = pkg.get("dependencies", {}) + + if "mocha" in dev_deps or "mocha" in deps: + return ("mocha", ["npx", "mocha", "--reporter", "spec"]) + + test_script = pkg.get("scripts", {}).get("test", "") + if test_script and "no test specified" not in test_script: + return ("npm-test", ["npm", "test"]) + except (OSError, json.JSONDecodeError): + pass + + # Go + if "go.mod" in entries: + return ("go", ["go", "test", "./...", "-count=1"]) + + # Rust + if "Cargo.toml" in entries: + return ("cargo", ["cargo", "test"]) + + return ("", []) + + +def main(): + try: + json.load(sys.stdin) + except (json.JSONDecodeError, ValueError): + pass + + cwd = os.getcwd() + framework, cmd = detect_test_framework(cwd) + + if not framework: + sys.exit(0) + + try: + result = subprocess.run( + cmd, + cwd=cwd, + capture_output=True, + text=True, + timeout=TIMEOUT_SECONDS, + ) + except subprocess.TimeoutExpired: + # Timeout is not a definitive failure — allow completion but warn + print( + f"Tests timed out ({framework}, {TIMEOUT_SECONDS}s). " + f"Task completion allowed — verify tests manually.", + file=sys.stderr, + ) + sys.exit(0) + except FileNotFoundError: + sys.exit(0) + except OSError: + sys.exit(0) + + if result.returncode == 0: + sys.exit(0) + + output = (result.stdout + "\n" + result.stderr).strip() + if not output: + output = "(no test output)" + + lines = output.splitlines() + if len(lines) > 50: + output = "...(truncated)\n" + "\n".join(lines[-50:]) + + print( + f"Tests failed ({framework}). Fix failures before marking task complete:\n{output}", + file=sys.stderr, + ) + sys.exit(2) + + +if __name__ == "__main__": + main() diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/teammate-idle-check.py b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/teammate-idle-check.py new file mode 100644 index 0000000..ff8a92f --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/teammate-idle-check.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +""" +TeammateIdle quality gate — checks if teammate has incomplete tasks. + +Runs when a teammate is about to go idle. Queries the shared task list +directory for tasks assigned to this teammate that aren't yet completed. + +Exit 0: Allow idle (no incomplete tasks or unable to determine) +Exit 2: Send feedback via stderr (incomplete tasks found) +""" + +import json +import os +import sys + + +def find_incomplete_tasks(teammate_name: str) -> list[str]: + """Scan task directories for incomplete tasks owned by this teammate.""" + config_dir = os.environ.get("CLAUDE_CONFIG_DIR", os.path.expanduser("~/.claude")) + tasks_base = os.path.join(config_dir, "tasks") + + if not os.path.isdir(tasks_base): + return [] + + incomplete = [] + for entry in os.listdir(tasks_base): + team_dir = os.path.join(tasks_base, entry) + if not os.path.isdir(team_dir): + continue + + for filename in sorted(os.listdir(team_dir)): + if not filename.endswith(".json"): + continue + + task_path = os.path.join(team_dir, filename) + try: + with open(task_path, "r", encoding="utf-8") as f: + task = json.load(f) + + owner = task.get("owner", "") + status = task.get("status", "") + subject = task.get("subject", filename) + + if owner == teammate_name and status in ("pending", "in_progress"): + incomplete.append(subject) + except (OSError, json.JSONDecodeError, ValueError): + continue + + return incomplete + + +def main(): + try: + input_data = json.load(sys.stdin) + except (json.JSONDecodeError, ValueError): + sys.exit(0) + + teammate_name = ( + input_data.get("teammate_name") + or input_data.get("agent_name") + or "" + ) + if not teammate_name: + sys.exit(0) + + incomplete = find_incomplete_tasks(teammate_name) + if not incomplete: + sys.exit(0) + + task_list = "; ".join(incomplete[:5]) + suffix = f" (and {len(incomplete) - 5} more)" if len(incomplete) > 5 else "" + print( + f"You have {len(incomplete)} incomplete task(s): {task_list}{suffix}. " + f"Check TaskList and continue working before going idle.", + file=sys.stderr, + ) + sys.exit(2) + + +if __name__ == "__main__": + main() diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py index d573f62..428fb6e 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py @@ -178,7 +178,10 @@ def main(): # Timeout is non-critical for PostToolUse — don't block the agent json.dump( { - "additionalContext": f"[Tests] {framework} timed out after 60s — skipping regression check." + "hookSpecificOutput": { + "hookEventName": "PostToolUse", + "additionalContext": f"[Tests] {framework} timed out after 60s — skipping regression check.", + } }, sys.stdout, ) @@ -199,19 +202,20 @@ def main(): if result.returncode != 0: edited = os.path.basename(file_path) - json.dump( - { - "error": ( - f"Regression detected after editing {edited} " - f"({framework}). Fix the failing tests before continuing:\n{output}" - ) - }, - sys.stdout, + print( + f"Regression detected after editing {edited} " + f"({framework}). Fix the failing tests before continuing:\n{output}", + file=sys.stderr, ) sys.exit(2) json.dump( - {"additionalContext": f"[Tests] No regression ({framework}): all tests passed"}, + { + "hookSpecificOutput": { + "hookEventName": "PostToolUse", + "additionalContext": f"[Tests] No regression ({framework}): all tests passed", + } + }, sys.stdout, ) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-tests-pass.py b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-tests-pass.py index ee0b143..9df9acd 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-tests-pass.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-tests-pass.py @@ -136,12 +136,7 @@ def main(): timeout=60, ) except subprocess.TimeoutExpired: - json.dump( - { - "additionalContext": f"[Tests] {framework} timed out after 60s. Consider running tests manually." - }, - sys.stdout, - ) + print(f"Tests timed out ({framework})", file=sys.stderr) sys.exit(2) except FileNotFoundError: # Test runner not installed — non-critical @@ -159,16 +154,9 @@ def main(): output = "...(truncated)\n" + "\n".join(lines[-50:]) if result.returncode != 0: - json.dump( - {"error": f"Tests failed ({framework}):\n{output}"}, - sys.stdout, - ) + print(f"Tests failed ({framework}):\n{output}", file=sys.stderr) sys.exit(2) - json.dump( - {"additionalContext": f"[Tests] All tests passed ({framework})"}, - sys.stdout, - ) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/commands/debug.md b/.devcontainer/plugins/devs-marketplace/plugins/agent-system/skills/debug/SKILL.md similarity index 100% rename from .devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/commands/debug.md rename to .devcontainer/plugins/devs-marketplace/plugins/agent-system/skills/debug/SKILL.md diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md b/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md index 5b0672d..4a607e7 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md @@ -50,45 +50,31 @@ Biome is resolved in this order: ## Installation -### 1. Place the plugin +### CodeForge DevContainer -Copy the `auto-code-quality/` directory into your Claude Code plugin marketplace: +Pre-installed and activated automatically — no setup needed. -``` -your-marketplace/ -├── .claude-plugin/ -│ └── marketplace.json -└── plugins/ - └── auto-code-quality/ ← this directory -``` +### From GitHub -### 2. Register in marketplace.json +Use this plugin in any Claude Code setup: -Add this entry to your `marketplace.json` `plugins` array: - -```json -{ - "name": "auto-code-quality", - "description": "Self-contained code quality: auto-format + auto-lint edited files", - "version": "1.0.0", - "source": "./plugins/auto-code-quality", - "category": "development" -} -``` +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: -### 3. Enable in settings.json + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` -Add to your Claude Code `settings.json` under `enabledPlugins`: +2. Enable the plugin in your `.claude/settings.json`: -```json -{ - "enabledPlugins": { - "auto-code-quality@your-marketplace": true - } -} -``` + ```json + { + "enabledPlugins": { + "auto-code-quality@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` -Replace `your-marketplace` with the name of your marketplace. + Replace `` with the absolute path to your CodeForge clone. ## How It Works diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/hooks/hooks.json index abfdc8e..b6ba889 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/hooks/hooks.json @@ -20,7 +20,6 @@ ], "Stop": [ { - "matcher": "", "hooks": [ { "type": "command", @@ -31,6 +30,11 @@ "type": "command", "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/lint-file.py", "timeout": 60 + }, + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/advisory-test-runner.py", + "timeout": 20 } ] } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/advisory-test-runner.py b/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/advisory-test-runner.py index d462f05..f9d9ca1 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/advisory-test-runner.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/advisory-test-runner.py @@ -4,11 +4,11 @@ Reads the list of files edited this session (written by collect-edited-files.py), maps them to affected test files, and runs only those tests. Skips entirely -if no files were edited. Results are returned as additionalContext so Claude -sees pass/fail info without being blocked. +if no files were edited. Results are returned as systemMessage (pass/timeout) or decision/reason +block (failure) so Claude acts on test failures before finishing. Reads hook input from stdin (JSON). Returns JSON on stdout. -Always exits 0 (advisory, never blocking). +Always exits 0. Failures use decision: "block" to prevent stopping. """ import json @@ -310,9 +310,7 @@ def main(): ) except subprocess.TimeoutExpired: json.dump( - { - "additionalContext": f"[Tests] {framework} timed out after {TIMEOUT_SECONDS}s" - }, + {"systemMessage": f"[Tests] {framework} timed out after {TIMEOUT_SECONDS}s"}, sys.stdout, ) sys.exit(0) @@ -323,7 +321,7 @@ def main(): if result.returncode == 0: json.dump( - {"additionalContext": f"[Tests] All tests passed ({framework})"}, + {"systemMessage": f"[Tests] All tests passed ({framework})"}, sys.stdout, ) sys.exit(0) @@ -337,7 +335,10 @@ def main(): output = "...(truncated)\n" + "\n".join(lines[-30:]) json.dump( - {"additionalContext": (f"[Tests] Some tests FAILED ({framework}):\n{output}")}, + { + "decision": "block", + "reason": f"[Tests] Some tests FAILED ({framework}):\n{output}", + }, sys.stdout, ) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json b/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json deleted file mode 100644 index a00ac28..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "auto-formatter", - "description": "Batch-formats edited files at Stop (Ruff for Python, gofmt for Go, Biome for JS/TS/CSS/JSON/GraphQL/HTML, shfmt for Shell, dprint for Markdown/YAML/TOML/Dockerfile, rustfmt for Rust)", - "author": { - "name": "AnExiledDev" - } -} diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/README.md b/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/README.md deleted file mode 100644 index 27e9caf..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# auto-formatter - -Claude Code plugin that batch-formats edited files when Claude finishes responding. Reads file paths collected by the `code-directive` plugin's `collect-edited-files.py` hook and formats each file based on its extension. - -## What It Does - -When Claude stops responding, the plugin reads the session's list of edited files and formats each one using the appropriate tool: - -| Language / File Type | Formatter | Fallback | -|----------------------|-----------|----------| -| Python (`.py`, `.pyi`) | [ruff format](https://docs.astral.sh/ruff/) | [black](https://github.com/psf/black) | -| Go (`.go`) | gofmt (bundled with Go) | — | -| JS/TS/CSS/JSON/GraphQL/HTML (`.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.json`, `.jsonc`, `.graphql`, `.gql`, `.html`, `.vue`, `.svelte`, `.astro`) | [biome](https://biomejs.dev/) check --write | — | -| Shell (`.sh`, `.bash`, `.zsh`, `.mksh`, `.bats`) | [shfmt](https://github.com/mvdan/sh) | — | -| Markdown/YAML/TOML (`.md`, `.markdown`, `.yaml`, `.yml`, `.toml`) | [dprint](https://dprint.dev/) | — | -| Dockerfile | dprint | — | -| Rust (`.rs`) | rustfmt (bundled with Rust) | — | - -All formatting is non-blocking. Missing tools are silently skipped. The plugin always exits 0 — it will never interrupt Claude. - -## How It Works - -### Hook Lifecycle - -``` -code-directive's collect-edited-files.py (PostToolUse on Edit/Write) - │ - └─→ Appends edited file path to /tmp/claude-edited-files-{session_id} - │ - │ ... Claude keeps working ... - │ -Claude stops responding (Stop event) - │ - └─→ format-on-stop.py reads the temp file, deduplicates paths, - formats each file by extension, then cleans up the temp file -``` - -### Dependency on code-directive - -This plugin does **not** collect file paths itself. It relies on the `code-directive` plugin's `collect-edited-files.py` PostToolUse hook to write edited file paths to `/tmp/claude-edited-files-{session_id}`. Both plugins must be enabled for formatting to work. - -### Biome Discovery - -Biome is resolved in this order: -1. **Project-local**: walks up from the edited file looking for `node_modules/.bin/biome` -2. **Global**: checks PATH via `which biome` - -### dprint Configuration - -The dprint formatter looks for a config file at `/usr/local/share/dprint/dprint.json`. If this file doesn't exist, dprint formatting is skipped. - -### Timeouts - -| Scope | Timeout | -|-------|---------| -| Entire Stop hook | 15s | -| Individual tool invocation | 10-12s | - -## Conflict Warning - -Do **not** enable this plugin alongside `auto-code-quality`. That plugin bundles its own formatter with the same functionality. Enabling both won't corrupt data (different temp file prefixes: `claude-edited-files-*` vs `claude-cq-*`), but files would be formatted twice. - -## Plugin Structure - -``` -auto-formatter/ -├── .claude-plugin/ -│ └── plugin.json # Plugin metadata -├── hooks/ -│ └── hooks.json # Stop hook registration -├── scripts/ -│ └── format-on-stop.py # Batch formatter (Stop) -└── README.md # This file -``` - -## Requirements - -- Python 3.11+ -- Claude Code with plugin hook support -- `code-directive` plugin enabled (provides the file path collector) -- Install the formatting tools for the languages you work with — everything is optional diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json deleted file mode 100644 index 7be41b6..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "description": "Batch-format collected files when Claude stops responding", - "hooks": { - "Stop": [ - { - "matcher": "", - "hooks": [ - { - "type": "command", - "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/format-on-stop.py", - "timeout": 15 - } - ] - } - ] - } -} diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py b/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py deleted file mode 100644 index 182d219..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py +++ /dev/null @@ -1,297 +0,0 @@ -#!/usr/bin/env python3 -""" -Unified batch formatter — runs as a Stop hook. - -Reads file paths collected by collect-edited-files.py during the -conversation turn, deduplicates them, and formats each based on -extension: - .py / .pyi → Ruff format (fallback: Black) - .go → gofmt - .js/.jsx/.ts/.tsx/.mjs/.cjs/.mts/.cts → Biome check --write - .css/.json/.jsonc/.graphql/.gql → Biome check --write - .html/.vue/.svelte/.astro → Biome check --write - .sh/.bash/.zsh/.mksh/.bats → shfmt -w - .md/.markdown → dprint fmt - .yaml/.yml → dprint fmt - .toml → dprint fmt - Dockerfile / .dockerfile → dprint fmt - .rs → rustfmt - -Always cleans up the temp file. Always exits 0. -""" - -import json -import os -import subprocess -import sys -from pathlib import Path - -# ── Extension sets ────────────────────────────────────────────────── - -PYTHON_EXTS = {".py", ".pyi"} -GO_EXTS = {".go"} -BIOME_EXTS = { - ".js", - ".jsx", - ".ts", - ".tsx", - ".mjs", - ".cjs", - ".mts", - ".cts", - ".css", - ".json", - ".jsonc", - ".graphql", - ".gql", - ".html", - ".vue", - ".svelte", - ".astro", -} -SHELL_EXTS = {".sh", ".bash", ".zsh", ".mksh", ".bats"} -DPRINT_EXTS = {".md", ".markdown", ".yaml", ".yml", ".toml"} -RUST_EXTS = {".rs"} - -# ── Fallback paths ────────────────────────────────────────────────── - -BLACK_PATH_FALLBACK = "/usr/local/py-utils/bin/black" -GOFMT_PATH_FALLBACK = "/usr/local/go/bin/gofmt" -DPRINT_CONFIG = "/usr/local/share/dprint/dprint.json" - -# ── Tool resolution ───────────────────────────────────────────────── - - -def _resolve_tool(name: str, fallback: str = "") -> str | None: - """Find tool via PATH first, fall back to hardcoded path.""" - try: - result = subprocess.run(["which", name], capture_output=True, text=True) - if result.returncode == 0: - return result.stdout.strip() - except Exception: - pass - if fallback and os.path.exists(fallback): - return fallback - return None - - -def find_tool_upward(file_path: str, tool_name: str) -> str | None: - """Walk up from file directory looking for node_modules/.bin/.""" - current = Path(file_path).parent - for _ in range(20): - candidate = current / "node_modules" / ".bin" / tool_name - if candidate.is_file(): - return str(candidate) - parent = current.parent - if parent == current: - break - current = parent - return None - - -def find_global_tool(tool_name: str) -> str | None: - """Check if tool is available globally.""" - try: - result = subprocess.run( - ["which", tool_name], - capture_output=True, - text=True, - ) - if result.returncode == 0: - return result.stdout.strip() - except Exception: - pass - return None - - -def find_biome(file_path: str) -> str | None: - """Find biome binary: project-local first, then global.""" - local = find_tool_upward(file_path, "biome") - if local: - return local - return find_global_tool("biome") - - -# ── Formatters ────────────────────────────────────────────────────── - - -def format_python(file_path: str) -> None: - """Format with Ruff (preferred) or Black (fallback).""" - ruff = _resolve_tool("ruff") - if ruff: - try: - subprocess.run( - [ruff, "format", "--quiet", file_path], - capture_output=True, - timeout=10, - ) - return - except (subprocess.TimeoutExpired, OSError): - pass - - # Fallback to Black - black = _resolve_tool("black", BLACK_PATH_FALLBACK) - if not black: - return - try: - subprocess.run( - [black, "--quiet", file_path], - capture_output=True, - timeout=10, - ) - except (subprocess.TimeoutExpired, OSError): - pass - - -def format_go(file_path: str) -> None: - """Format with gofmt.""" - gofmt = _resolve_tool("gofmt", GOFMT_PATH_FALLBACK) - if not gofmt: - return - try: - subprocess.run( - [gofmt, "-w", file_path], - capture_output=True, - timeout=10, - ) - except (subprocess.TimeoutExpired, OSError): - pass - - -def format_biome(file_path: str) -> None: - """Format with Biome in safe mode (no --unsafe).""" - biome = find_biome(file_path) - if not biome: - return - try: - subprocess.run( - [biome, "check", "--write", file_path], - capture_output=True, - timeout=12, - ) - except (subprocess.TimeoutExpired, OSError): - pass - - -def format_shell(file_path: str) -> None: - """Format with shfmt.""" - shfmt = _resolve_tool("shfmt") - if not shfmt: - return - try: - subprocess.run( - [shfmt, "-w", file_path], - capture_output=True, - timeout=10, - ) - except (subprocess.TimeoutExpired, OSError): - pass - - -def format_dprint(file_path: str) -> None: - """Format with dprint using the global config.""" - dprint = _resolve_tool("dprint") - if not dprint: - return - if not os.path.isfile(DPRINT_CONFIG): - return - try: - subprocess.run( - [dprint, "fmt", "--config", DPRINT_CONFIG, file_path], - capture_output=True, - timeout=10, - ) - except (subprocess.TimeoutExpired, OSError): - pass - - -def format_rust(file_path: str) -> None: - """Format with rustfmt (conditional — only if installed).""" - rustfmt = _resolve_tool("rustfmt") - if not rustfmt: - return - try: - subprocess.run( - [rustfmt, file_path], - capture_output=True, - timeout=10, - ) - except (subprocess.TimeoutExpired, OSError): - pass - - -# ── Dispatch ──────────────────────────────────────────────────────── - - -def format_file(file_path: str) -> None: - """Dispatch to the correct formatter based on extension / filename.""" - path = Path(file_path) - ext = path.suffix.lower() - name = path.name - - if ext in PYTHON_EXTS: - format_python(file_path) - elif ext in GO_EXTS: - format_go(file_path) - elif ext in BIOME_EXTS: - format_biome(file_path) - elif ext in SHELL_EXTS: - format_shell(file_path) - elif ext in DPRINT_EXTS: - format_dprint(file_path) - elif ext in RUST_EXTS: - format_rust(file_path) - elif name == "Dockerfile" or ext == ".dockerfile": - format_dprint(file_path) - - -# ── Main ──────────────────────────────────────────────────────────── - - -def main(): - try: - input_data = json.load(sys.stdin) - except (json.JSONDecodeError, ValueError): - sys.exit(0) - - # Prevent infinite loops if Stop hook triggers another stop - if input_data.get("stop_hook_active"): - sys.exit(0) - - session_id = input_data.get("session_id", "") - if not session_id: - sys.exit(0) - - tmp_path = f"/tmp/claude-edited-files-{session_id}" - - try: - with open(tmp_path) as f: - raw_paths = f.read().splitlines() - except FileNotFoundError: - sys.exit(0) - except OSError: - sys.exit(0) - finally: - # Always clean up the temp file - try: - os.unlink(tmp_path) - except OSError: - pass - - # Deduplicate while preserving order, filter to existing files - seen: set[str] = set() - paths: list[str] = [] - for p in raw_paths: - p = p.strip() - if p and p not in seen and os.path.isfile(p): - seen.add(p) - paths.append(p) - - for path in paths: - format_file(path) - - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json b/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json deleted file mode 100644 index e238298..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "auto-linter", - "description": "Auto-lints edited files at Stop (Pyright + Ruff for Python, Biome for JS/TS/CSS/GraphQL, ShellCheck for Shell, go vet for Go, hadolint for Dockerfile, clippy for Rust)", - "author": { - "name": "AnExiledDev" - } -} diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/README.md b/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/README.md deleted file mode 100644 index 1e3bc67..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# auto-linter - -Claude Code plugin that batch-lints edited files when Claude finishes responding. Reads file paths collected by the `code-directive` plugin's `collect-edited-files.py` hook and lints each file using the appropriate tool. Lint results are returned as advisory context — never blocking. - -## What It Does - -When Claude stops responding, the plugin reads the session's list of edited files, lints each one, and injects any warnings as `additionalContext` so Claude sees them on its next response. - -| Language / File Type | Linter(s) | -|----------------------|-----------| -| Python (`.py`, `.pyi`) | [pyright](https://github.com/microsoft/pyright) (type checking) + [ruff check](https://docs.astral.sh/ruff/) (style/correctness) | -| JS/TS/CSS/GraphQL (`.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.graphql`, `.gql`) | [biome lint](https://biomejs.dev/) | -| Shell (`.sh`, `.bash`, `.zsh`, `.mksh`, `.bats`) | [shellcheck](https://github.com/koalaman/shellcheck) | -| Go (`.go`) | go vet (bundled with Go) | -| Dockerfile | [hadolint](https://github.com/hadolint/hadolint) | -| Rust (`.rs`) | [clippy](https://doc.rust-lang.org/clippy/) (via cargo) | - -All linting is non-blocking. Missing tools are silently skipped. The plugin always exits 0 and returns warnings as `additionalContext` — it will never interrupt Claude. - -## How It Works - -### Hook Lifecycle - -``` -code-directive's collect-edited-files.py (PostToolUse on Edit/Write) - │ - └─→ Appends edited file path to /tmp/claude-lint-files-{session_id} - │ - │ ... Claude keeps working ... - │ -Claude stops responding (Stop event) - │ - └─→ lint-file.py reads the temp file, deduplicates paths, - lints each file by extension, groups results by linter, - injects warnings as additionalContext, then cleans up -``` - -### Dependency on code-directive - -This plugin relies on the `code-directive` plugin's `collect-edited-files.py` PostToolUse hook to write edited file paths to `/tmp/claude-lint-files-{session_id}`. Both plugins must be enabled for linting to work. - -### Output Format - -Lint results are grouped by linter and returned as `additionalContext`. Each file shows up to 5 issues with severity, line number, and message: - -``` -[Auto-linter] Pyright results: - example.py: 2 issue(s) - ✗ Line 15: Cannot assign type "str" to declared type "int" - ! Line 42: Variable "x" is not defined - -[Auto-linter] Ruff results: - example.py: 1 issue(s) - ! Line 8: [F401] `os` imported but unused -``` - -### Biome Discovery - -Biome is resolved in this order: -1. **Project-local**: walks up from the edited file looking for `node_modules/.bin/biome` -2. **Global**: checks PATH via `which biome` - -### Timeouts - -| Scope | Timeout | -|-------|---------| -| Entire Stop hook | 60s | -| Individual tool invocation | 10s | - -## Conflict Warning - -Do **not** enable this plugin alongside `auto-code-quality`. That plugin bundles its own linter with the same functionality. Enabling both won't corrupt data (different temp file prefixes: `claude-lint-files-*` vs `claude-cq-*`), but files would be linted twice. - -## Plugin Structure - -``` -auto-linter/ -├── .claude-plugin/ -│ └── plugin.json # Plugin metadata -├── hooks/ -│ └── hooks.json # Stop hook registration -├── scripts/ -│ └── lint-file.py # Batch linter (Stop) -└── README.md # This file -``` - -## Requirements - -- Python 3.11+ -- Claude Code with plugin hook support -- `code-directive` plugin enabled (provides the file path collector) -- Install the linting tools for the languages you work with — everything is optional diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json deleted file mode 100644 index db11444..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "description": "Batch-lint collected files when Claude stops responding", - "hooks": { - "Stop": [ - { - "matcher": "", - "hooks": [ - { - "type": "command", - "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/lint-file.py", - "timeout": 60 - } - ] - } - ] - } -} diff --git a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py b/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py deleted file mode 100644 index 9c1be1b..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +++ /dev/null @@ -1,536 +0,0 @@ -#!/usr/bin/env python3 -""" -Batch linter — runs as a Stop hook. - -Reads file paths collected by collect-edited-files.py during the -conversation turn, deduplicates them, and lints each based on -extension: - .py / .pyi → Pyright (type checking) + Ruff check (style/correctness) - .js/.jsx/.ts/… → Biome lint - .css/.graphql/… → Biome lint - .sh/.bash/.zsh/… → ShellCheck - .go → go vet - Dockerfile → hadolint - .rs → clippy (conditional) - -Outputs JSON with additionalContext containing lint warnings. -Always cleans up the temp file. Always exits 0. -""" - -import json -import os -import subprocess -import sys -from pathlib import Path - -# ── Extension sets ────────────────────────────────────────────────── - -PYTHON_EXTS = {".py", ".pyi"} -BIOME_EXTS = { - ".js", - ".jsx", - ".ts", - ".tsx", - ".mjs", - ".cjs", - ".mts", - ".cts", - ".css", - ".graphql", - ".gql", -} -SHELL_EXTS = {".sh", ".bash", ".zsh", ".mksh", ".bats"} -GO_EXTS = {".go"} -RUST_EXTS = {".rs"} - -SUBPROCESS_TIMEOUT = 10 - - -# ── Tool resolution ───────────────────────────────────────────────── - - -def _which(name: str) -> str | None: - """Check if a tool is available in PATH.""" - try: - result = subprocess.run(["which", name], capture_output=True, text=True) - if result.returncode == 0: - return result.stdout.strip() - except Exception: - pass - return None - - -def _find_tool_upward(file_path: str, tool_name: str) -> str | None: - """Walk up from file directory looking for node_modules/.bin/.""" - current = Path(file_path).parent - for _ in range(20): - candidate = current / "node_modules" / ".bin" / tool_name - if candidate.is_file(): - return str(candidate) - parent = current.parent - if parent == current: - break - current = parent - return None - - -def _find_biome(file_path: str) -> str | None: - """Find biome binary: project-local first, then global.""" - local = _find_tool_upward(file_path, "biome") - if local: - return local - return _which("biome") - - -# ── Diagnostic formatting ────────────────────────────────────────── - - -def _format_issues(filename: str, diagnostics: list[dict]) -> str: - """Format a list of {severity, line, message} dicts into display text.""" - if not diagnostics: - return "" - - issues = [] - for diag in diagnostics[:5]: - severity = diag.get("severity", "info") - message = diag.get("message", "") - line = diag.get("line", 0) - - if severity == "error": - icon = "\u2717" - elif severity == "warning": - icon = "!" - else: - icon = "\u2022" - - issues.append(f" {icon} Line {line}: {message}") - - total = len(diagnostics) - shown = min(5, total) - header = f" {filename}: {total} issue(s)" - if total > shown: - header += f" (showing first {shown})" - - return header + "\n" + "\n".join(issues) - - -# ── Linters ───────────────────────────────────────────────────────── - - -def lint_python_pyright(file_path: str) -> str: - """Run Pyright type checker on a Python file.""" - pyright = _which("pyright") - if not pyright: - return "" - - try: - result = subprocess.run( - [pyright, "--outputjson", file_path], - capture_output=True, - text=True, - timeout=SUBPROCESS_TIMEOUT, - ) - - try: - output = json.loads(result.stdout) - except json.JSONDecodeError: - return "" - - diagnostics = output.get("generalDiagnostics", []) - if not diagnostics: - return "" - - parsed = [ - { - "severity": d.get("severity", "info"), - "line": d.get("range", {}).get("start", {}).get("line", 0) + 1, - "message": d.get("message", ""), - } - for d in diagnostics - ] - return _format_issues(Path(file_path).name, parsed) - - except subprocess.TimeoutExpired: - return f" {Path(file_path).name}: pyright timed out" - except Exception: - return "" - - -def lint_python_ruff(file_path: str) -> str: - """Run Ruff linter on a Python file.""" - ruff = _which("ruff") - if not ruff: - return "" - - try: - result = subprocess.run( - [ruff, "check", "--output-format=json", "--no-fix", file_path], - capture_output=True, - text=True, - timeout=SUBPROCESS_TIMEOUT, - ) - - try: - issues = json.loads(result.stdout) - except json.JSONDecodeError: - return "" - - if not issues: - return "" - - parsed = [ - { - "severity": "warning", - "line": issue.get("location", {}).get("row", 0), - "message": f"[{issue.get('code', '?')}] {issue.get('message', '')}", - } - for issue in issues - ] - return _format_issues(Path(file_path).name, parsed) - - except subprocess.TimeoutExpired: - return f" {Path(file_path).name}: ruff timed out" - except Exception: - return "" - - -def lint_biome(file_path: str) -> str: - """Run Biome linter for JS/TS/CSS/GraphQL files.""" - biome = _find_biome(file_path) - if not biome: - return "" - - try: - result = subprocess.run( - [biome, "lint", "--reporter=json", file_path], - capture_output=True, - text=True, - timeout=SUBPROCESS_TIMEOUT, - ) - - try: - output = json.loads(result.stdout) - except json.JSONDecodeError: - return "" - - diagnostics = output.get("diagnostics", []) - if not diagnostics: - return "" - - parsed = [ - { - "severity": d.get("severity", "warning"), - "line": ( - d.get("location", {}).get("span", {}).get("start", {}) - if isinstance( - d.get("location", {}).get("span", {}).get("start"), int - ) - else 0 - ), - "message": d.get("description", d.get("message", "")), - } - for d in diagnostics - ] - return _format_issues(Path(file_path).name, parsed) - - except subprocess.TimeoutExpired: - return f" {Path(file_path).name}: biome lint timed out" - except Exception: - return "" - - -def lint_shellcheck(file_path: str) -> str: - """Run ShellCheck on a shell script.""" - shellcheck = _which("shellcheck") - if not shellcheck: - return "" - - try: - result = subprocess.run( - [shellcheck, "--format=json", file_path], - capture_output=True, - text=True, - timeout=SUBPROCESS_TIMEOUT, - ) - - try: - issues = json.loads(result.stdout) - except json.JSONDecodeError: - return "" - - if not issues: - return "" - - severity_map = { - "error": "error", - "warning": "warning", - "info": "info", - "style": "info", - } - parsed = [ - { - "severity": severity_map.get(issue.get("level", "info"), "info"), - "line": issue.get("line", 0), - "message": f"[SC{issue.get('code', '?')}] {issue.get('message', '')}", - } - for issue in issues - ] - return _format_issues(Path(file_path).name, parsed) - - except subprocess.TimeoutExpired: - return f" {Path(file_path).name}: shellcheck timed out" - except Exception: - return "" - - -def lint_go_vet(file_path: str) -> str: - """Run go vet on a Go file.""" - go = _which("go") - if not go: - return "" - - try: - result = subprocess.run( - [go, "vet", file_path], - capture_output=True, - text=True, - timeout=SUBPROCESS_TIMEOUT, - ) - - # go vet outputs to stderr - output = result.stderr.strip() - if not output: - return "" - - lines = output.splitlines() - parsed = [] - for line in lines: - # Format: file.go:LINE:COL: message - parts = line.split(":", 3) - if len(parts) >= 4: - try: - line_num = int(parts[1]) - except ValueError: - line_num = 0 - parsed.append( - { - "severity": "warning", - "line": line_num, - "message": parts[3].strip(), - } - ) - elif line.strip(): - parsed.append( - { - "severity": "warning", - "line": 0, - "message": line.strip(), - } - ) - - return _format_issues(Path(file_path).name, parsed) - - except subprocess.TimeoutExpired: - return f" {Path(file_path).name}: go vet timed out" - except Exception: - return "" - - -def lint_hadolint(file_path: str) -> str: - """Run hadolint on a Dockerfile.""" - hadolint = _which("hadolint") - if not hadolint: - return "" - - try: - result = subprocess.run( - [hadolint, "--format", "json", file_path], - capture_output=True, - text=True, - timeout=SUBPROCESS_TIMEOUT, - ) - - try: - issues = json.loads(result.stdout) - except json.JSONDecodeError: - return "" - - if not issues: - return "" - - severity_map = { - "error": "error", - "warning": "warning", - "info": "info", - "style": "info", - } - parsed = [ - { - "severity": severity_map.get(issue.get("level", "info"), "info"), - "line": issue.get("line", 0), - "message": f"[{issue.get('code', '?')}] {issue.get('message', '')}", - } - for issue in issues - ] - return _format_issues(Path(file_path).name, parsed) - - except subprocess.TimeoutExpired: - return f" {Path(file_path).name}: hadolint timed out" - except Exception: - return "" - - -def lint_clippy(file_path: str) -> str: - """Run clippy on a Rust file (conditional — only if cargo is in PATH).""" - cargo = _which("cargo") - if not cargo: - return "" - - try: - result = subprocess.run( - [cargo, "clippy", "--message-format=json", "--", "-W", "clippy::all"], - capture_output=True, - text=True, - timeout=SUBPROCESS_TIMEOUT, - cwd=str(Path(file_path).parent), - ) - - lines = result.stdout.strip().splitlines() - parsed = [] - target_name = Path(file_path).name - - for line in lines: - try: - msg = json.loads(line) - except json.JSONDecodeError: - continue - - if msg.get("reason") != "compiler-message": - continue - inner = msg.get("message", {}) - level = inner.get("level", "") - if level not in ("warning", "error"): - continue - - # Match diagnostics to the target file - spans = inner.get("spans", []) - line_num = 0 - for span in spans: - if span.get("is_primary") and target_name in span.get("file_name", ""): - line_num = span.get("line_start", 0) - break - - if line_num or not spans: - parsed.append( - { - "severity": level, - "line": line_num, - "message": inner.get("message", ""), - } - ) - - return _format_issues(Path(file_path).name, parsed) - - except subprocess.TimeoutExpired: - return f" {Path(file_path).name}: clippy timed out" - except Exception: - return "" - - -# ── Main ──────────────────────────────────────────────────────────── - - -def main(): - try: - input_data = json.load(sys.stdin) - except (json.JSONDecodeError, ValueError): - sys.exit(0) - - if input_data.get("stop_hook_active"): - sys.exit(0) - - session_id = input_data.get("session_id", "") - if not session_id: - sys.exit(0) - - tmp_path = f"/tmp/claude-lint-files-{session_id}" - - try: - with open(tmp_path) as f: - raw_paths = f.read().splitlines() - except FileNotFoundError: - sys.exit(0) - except OSError: - sys.exit(0) - finally: - try: - os.unlink(tmp_path) - except OSError: - pass - - # Deduplicate, filter to existing files (no longer Python-only) - seen: set[str] = set() - paths: list[str] = [] - for p in raw_paths: - p = p.strip() - if p and p not in seen and os.path.isfile(p): - seen.add(p) - paths.append(p) - - if not paths: - sys.exit(0) - - # Collect results grouped by linter - all_results: dict[str, list[str]] = {} - - for path in paths: - ext = Path(path).suffix.lower() - name = Path(path).name - - if ext in PYTHON_EXTS: - msg = lint_python_pyright(path) - if msg: - all_results.setdefault("Pyright", []).append(msg) - msg = lint_python_ruff(path) - if msg: - all_results.setdefault("Ruff", []).append(msg) - - elif ext in BIOME_EXTS: - msg = lint_biome(path) - if msg: - all_results.setdefault("Biome", []).append(msg) - - elif ext in SHELL_EXTS: - msg = lint_shellcheck(path) - if msg: - all_results.setdefault("ShellCheck", []).append(msg) - - elif ext in GO_EXTS: - msg = lint_go_vet(path) - if msg: - all_results.setdefault("go vet", []).append(msg) - - elif name == "Dockerfile" or ext == ".dockerfile": - msg = lint_hadolint(path) - if msg: - all_results.setdefault("hadolint", []).append(msg) - - elif ext in RUST_EXTS: - msg = lint_clippy(path) - if msg: - all_results.setdefault("clippy", []).append(msg) - - if all_results: - sections = [] - for linter_name, results in all_results.items(): - sections.append( - f"[Auto-linter] {linter_name} results:\n" + "\n".join(results) - ) - output = "\n\n".join(sections) - print(json.dumps({"additionalContext": output})) - - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/README.md b/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/README.md index 92ec390..2b2c74f 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/README.md @@ -20,6 +20,34 @@ The plugin uses the `lspServers` field in `plugin.json` to declare server config Each server maps file extensions to language identifiers. When Claude Code opens a file matching a registered extension, it routes it to the corresponding LSP server for diagnostics, completions, and other language features. +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "codeforge-lsp@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + ## Plugin Structure ``` diff --git a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md index 4ab88e2..d7c8371 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md @@ -53,6 +53,34 @@ Claude calls the Bash tool The hook has a 5-second timeout. If the script takes longer, Claude Code proceeds with the command. +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "dangerous-command-blocker@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + ## Plugin Structure ``` diff --git a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py index ed6243f..4c45eb9 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py @@ -116,8 +116,8 @@ def main(): is_dangerous, message = check_command(command) if is_dangerous: - # Output error message and exit 2 to block - print(json.dumps({"error": message})) + # Output error to stderr (exit 2 ignores stdout) + print(message, file=sys.stderr) sys.exit(2) # Allow command to proceed diff --git a/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/README.md b/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/README.md index 9a273af..9bb827a 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/README.md @@ -25,6 +25,34 @@ Claude stops responding (Stop event) The hook has a 5-second timeout. The plugin contains no scripts of its own — it delegates entirely to the `claude-notify` binary. +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "notify-hook@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + ## Plugin Structure ``` diff --git a/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json index 2cd21c6..c16046b 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json @@ -3,7 +3,6 @@ "hooks": { "Stop": [ { - "matcher": "", "hooks": [ { "type": "command", diff --git a/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md b/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md index 6146268..364387a 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md @@ -66,6 +66,34 @@ The Bash guard parses commands for write-indicating patterns and extracts the ta Both hooks have a 5-second timeout. +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "protected-files-guard@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + ## Plugin Structure ``` diff --git a/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py b/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py index 0e40314..d630e2d 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py @@ -104,7 +104,7 @@ def main(): for target in targets: is_protected, message = check_path(target) if is_protected: - print(json.dumps({"error": f"{message} (via bash command)"})) + print(f"{message} (via bash command)", file=sys.stderr) sys.exit(2) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py b/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py index 2536ba9..eb521d0 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py @@ -89,8 +89,8 @@ def main(): is_protected, message = check_path(file_path) if is_protected: - # Output error message and exit 2 to block - print(json.dumps({"error": message})) + # Output error to stderr (exit 2 ignores stdout) + print(message, file=sys.stderr) sys.exit(2) # Allow edit to proceed diff --git a/.devcontainer/plugins/devs-marketplace/plugins/session-context/.claude-plugin/plugin.json b/.devcontainer/plugins/devs-marketplace/plugins/session-context/.claude-plugin/plugin.json index c5e2fbd..ecfe5bd 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/session-context/.claude-plugin/plugin.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/session-context/.claude-plugin/plugin.json @@ -1,7 +1,6 @@ { "name": "session-context", "description": "Session lifecycle hooks: git state injection, TODO harvesting, and commit reminders", - "version": "1.0.0", "author": { "name": "AnExiledDev" } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/session-context/README.md b/.devcontainer/plugins/devs-marketplace/plugins/session-context/README.md new file mode 100644 index 0000000..e12a872 --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/plugins/session-context/README.md @@ -0,0 +1,140 @@ +# session-context + +Claude Code plugin that injects contextual information at session boundaries. Provides git state awareness at session start, surfaces TODO/FIXME markers, and reminds about uncommitted changes when Claude finishes responding. + +## What It Does + +Three hooks that run automatically at session lifecycle boundaries: + +| Phase | Script | What It Injects | +|-------|--------|-----------------| +| Session start | `git-state-injector.py` | Current branch, status, recent commits, uncommitted changes | +| Session start | `todo-harvester.py` | Count and top 10 TODO/FIXME/HACK/XXX markers in the codebase | +| Stop | `commit-reminder.py` | Advisory about staged/unstaged changes that should be committed | + +All hooks are non-blocking and cap their output to prevent context bloat. + +### Git State Injection + +Runs at session start and injects: +- Current branch name +- Working tree status (up to 20 lines) +- Recent commit log +- Diff stat of uncommitted changes (up to 15 lines) +- Total output capped at 2000 characters + +### TODO Harvesting + +Scans source files for tech debt markers and injects a summary: +- Searches for `TODO`, `FIXME`, `HACK`, `XXX` comments +- File types: `.py`, `.ts`, `.tsx`, `.js`, `.jsx`, `.go`, `.rs`, `.sh`, `.svelte`, `.vue`, `.rb`, `.java`, `.kt` +- Shows total count plus top 10 items +- Output capped at 800 characters + +### Commit Reminder + +Fires when Claude stops responding and checks for uncommitted work: +- Detects staged and unstaged changes +- Injects an advisory so Claude can naturally ask if the user wants to commit +- Uses a guard flag to prevent infinite loops (the reminder itself is a Stop event) + +## How It Works + +### Hook Lifecycle + +``` +Session starts + | + +-> SessionStart fires + | | + | +-> git-state-injector.py + | | | + | | +-> Runs git branch, status, log, diff --stat + | | +-> Caps output, injects as additionalContext + | | + | +-> todo-harvester.py + | | + | +-> Greps codebase for TODO/FIXME/HACK/XXX + | +-> Injects count + top 10 as additionalContext + | + | ... Claude works ... + | +Claude stops responding + | + +-> Stop fires + | + +-> commit-reminder.py + | + +-> Checks git status for changes + +-> Has changes? -> Inject commit advisory + +-> No changes? -> Silent (no output) +``` + +### Exit Code Behavior + +All three scripts exit 0 (advisory only). They never block operations. + +### Error Handling + +| Scenario | Behavior | +|----------|----------| +| Not a git repository | Silent exit (no output) | +| Git command failure | Silent exit (no output) | +| JSON parse failure | Silent exit | + +### Timeouts + +| Hook | Timeout | +|------|---------| +| Git state injection | 10s | +| TODO harvesting | 8s | +| Commit reminder | 8s | + +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "session-context@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + +## Plugin Structure + +``` +session-context/ ++-- .claude-plugin/ +| +-- plugin.json # Plugin metadata ++-- hooks/ +| +-- hooks.json # Hook registrations (SessionStart + Stop) ++-- scripts/ +| +-- git-state-injector.py # Git state context (SessionStart) +| +-- todo-harvester.py # Tech debt markers (SessionStart) +| +-- commit-reminder.py # Uncommitted changes advisory (Stop) ++-- README.md # This file +``` + +## Requirements + +- Python 3.11+ +- Git (for git state injection and commit reminders) +- Claude Code with plugin hook support diff --git a/.devcontainer/plugins/devs-marketplace/plugins/session-context/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/session-context/hooks/hooks.json index 6f6d7f1..b868078 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/session-context/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/session-context/hooks/hooks.json @@ -20,7 +20,6 @@ ], "Stop": [ { - "matcher": "", "hooks": [ { "type": "command", diff --git a/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py b/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py index 319a466..b317614 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py @@ -7,7 +7,8 @@ naturally ask the user if they want to commit. Reads hook input from stdin (JSON). Returns JSON on stdout. -Always exits 0 (advisory, never blocking). +Blocks with decision/reason so Claude addresses uncommitted changes +before finishing. The stop_hook_active guard prevents infinite loops. """ import json @@ -82,7 +83,7 @@ def main(): "Consider asking the user if they'd like to commit before finishing." ) - json.dump({"additionalContext": message}, sys.stdout) + json.dump({"decision": "block", "reason": message}, sys.stdout) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/git-state-injector.py b/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/git-state-injector.py index 2078541..ebc7070 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/git-state-injector.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/git-state-injector.py @@ -64,7 +64,15 @@ def main(): f"Working Directory: {cwd} — restrict all file operations to this " f"directory unless explicitly instructed otherwise." ) - json.dump({"additionalContext": output}, sys.stdout) + json.dump( + { + "hookSpecificOutput": { + "hookEventName": "SessionStart", + "additionalContext": output, + } + }, + sys.stdout, + ) sys.exit(0) sections = [] @@ -117,7 +125,15 @@ def main(): if len(output) > TOTAL_OUTPUT_CAP: output = output[:TOTAL_OUTPUT_CAP] + "\n...(truncated)" - json.dump({"additionalContext": output}, sys.stdout) + json.dump( + { + "hookSpecificOutput": { + "hookEventName": "SessionStart", + "additionalContext": output, + } + }, + sys.stdout, + ) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/todo-harvester.py b/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/todo-harvester.py index 14c5de0..b09dd11 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/todo-harvester.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/todo-harvester.py @@ -122,7 +122,15 @@ def main(): if len(body) > TOTAL_OUTPUT_CAP: body = body[:TOTAL_OUTPUT_CAP] + "\n...(truncated)" - json.dump({"additionalContext": body}, sys.stdout) + json.dump( + { + "hookSpecificOutput": { + "hookEventName": "SessionStart", + "additionalContext": body, + } + }, + sys.stdout, + ) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json index f43fb01..e23ce21 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json @@ -1,7 +1,6 @@ { "name": "skill-engine", "description": "21 coding knowledge packs with auto-suggestion for frameworks, tools, and patterns", - "version": "1.0.0", "author": { "name": "AnExiledDev" } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/README.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/README.md new file mode 100644 index 0000000..cc3a2ab --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/README.md @@ -0,0 +1,158 @@ +# skill-engine + +Claude Code plugin that provides 21 coding knowledge packs (skills) with automatic suggestion based on user prompts. Each skill contains domain-specific instructions and reference material that Claude loads on demand via the `/skill` command. + +## What It Does + +Two capabilities: + +1. **Skill library** — 21 skills covering frameworks, tools, and development patterns. Each skill is a structured knowledge pack with a `SKILL.md` entrypoint and `references/` subdirectory containing detailed reference docs. + +2. **Auto-suggestion** — A `UserPromptSubmit` hook watches user prompts for keyword matches and suggests relevant skills as context, so Claude can proactively load the right knowledge. + +### Skill Catalog + +| Skill | Domain | +|-------|--------| +| api-design | REST conventions, error handling, API patterns | +| ast-grep-patterns | Semantic code search patterns by language | +| claude-agent-sdk | Building custom agents with the Agent SDK (TypeScript) | +| claude-code-headless | CLI flags, output parsing, SDK and MCP integration | +| debugging | Error patterns, log locations, diagnosis procedures | +| dependency-management | Package managers, ecosystem commands, license compliance | +| docker | Dockerfile patterns, docker-compose services | +| docker-py | Docker SDK for Python, container lifecycle | +| documentation-patterns | API doc templates, docstring formats | +| fastapi | Routing, Pydantic v2, SSE streaming, middleware, dependencies | +| git-forensics | Advanced git commands, blame history, investigation playbooks | +| migration-patterns | Framework/version migrations for JavaScript and Python | +| performance-profiling | Profiling tools, interpreting results, optimization | +| pydantic-ai | Building AI agents with Pydantic, tools, models, streaming | +| refactoring-patterns | Safe transformations, code smell catalog | +| security-checklist | OWASP patterns, secrets management, vulnerability detection | +| skill-building | How to author skills, patterns and anti-patterns | +| sqlite | Schema, pragmas, advanced queries, FTS5, JS/Python patterns | +| svelte5 | Runes, reactivity, components, SPA routing, LayerCake | +| team | Agent team orchestration, parallel workstreams, task coordination | +| testing | Testing frameworks, FastAPI testing, Svelte testing | + +### Auto-Suggestion + +The `skill-suggester.py` hook matches user prompts against keyword maps defined in each skill. When a match is found, it injects a suggestion via `additionalContext` so Claude knows a relevant skill is available. + +Keywords are defined per skill as: +- **Phrases** — Multi-word patterns (e.g., "docker compose", "REST API") +- **Terms** — Single keywords (e.g., "FastAPI", "pytest") + +## How It Works + +### Hook Lifecycle + +``` +User submits a prompt + | + +-> UserPromptSubmit fires + | + +-> skill-suggester.py + | + +-> Scan prompt against all skill keyword maps + +-> Match found? -> Inject skill suggestion as additionalContext + +-> No match? -> Silent (no output) +``` + +### Skill Structure + +Each skill follows a standard layout: + +``` +skills/ ++-- skill-name/ + +-- SKILL.md # Entrypoint: instructions, patterns, key concepts + +-- references/ # Detailed reference material + +-- topic-a.md + +-- topic-b.md +``` + +Skills are loaded via Claude Code's `/skill` slash command (e.g., `/skill fastapi`). The `SKILL.md` file is the primary document Claude reads; references are loaded as needed for deeper detail. + +### Exit Code Behavior + +| Exit Code | Meaning | +|-----------|---------| +| 0 | Suggestion injected (or no match — silent) | + +The hook never blocks operations. + +### Timeouts + +| Hook | Timeout | +|------|---------| +| Skill suggestion (UserPromptSubmit) | 3s | + +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "skill-engine@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + +## Plugin Structure + +``` +skill-engine/ ++-- .claude-plugin/ +| +-- plugin.json # Plugin metadata ++-- hooks/ +| +-- hooks.json # UserPromptSubmit hook registration ++-- scripts/ +| +-- skill-suggester.py # Keyword-based skill auto-suggestion ++-- skills/ +| +-- api-design/ # 21 skill directories +| +-- ast-grep-patterns/ +| +-- claude-agent-sdk/ +| +-- claude-code-headless/ +| +-- debugging/ +| +-- dependency-management/ +| +-- docker/ +| +-- docker-py/ +| +-- documentation-patterns/ +| +-- fastapi/ +| +-- git-forensics/ +| +-- migration-patterns/ +| +-- performance-profiling/ +| +-- pydantic-ai/ +| +-- refactoring-patterns/ +| +-- security-checklist/ +| +-- skill-building/ +| +-- sqlite/ +| +-- svelte5/ +| +-- team/ +| +-- testing/ ++-- README.md # This file +``` + +## Requirements + +- Python 3.11+ +- Claude Code with plugin hook support (skills) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/hooks/hooks.json index 44518d7..28a5151 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/hooks/hooks.json @@ -1,21 +1,8 @@ { - "description": "Skill auto-suggestion on user prompts and Plan agent starts", + "description": "Skill auto-suggestion on user prompts", "hooks": { "UserPromptSubmit": [ { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/skill-suggester.py", - "timeout": 3 - } - ] - } - ], - "SubagentStart": [ - { - "matcher": "Plan", "hooks": [ { "type": "command", diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/scripts/skill-suggester.py b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/scripts/skill-suggester.py index 1a8890d..8ad1efd 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/scripts/skill-suggester.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/scripts/skill-suggester.py @@ -2,7 +2,7 @@ """Skill suggester hook for UserPromptSubmit and SubagentStart events. Detects which hook event called it via input JSON shape: -- UserPromptSubmit: {"prompt": "..."} -> {"systemMessage": "..."} +- UserPromptSubmit: {"prompt": "..."} -> {"additionalContext": "..."} - SubagentStart: {"subagent_type": "Plan", "prompt": "..."} -> {"additionalContext": "..."} Matches user prompts against skill keyword maps (phrases + terms) and suggests @@ -16,30 +16,33 @@ SKILLS = { "fastapi": { "phrases": [ - "rest api", + "build a fastapi app", + "rest api with fastapi", "fastapi", "fast api", + "add sse streaming", + "dependency injection in fastapi", + "define pydantic models", + "stream llm responses", + "add middleware to fastapi", "pydantic model", - "sse streaming", - "server-sent event", - "dependency injection", - "asgi middleware", - "api endpoint", - "api route", ], - "terms": ["fastapi", "pydantic", "uvicorn", "starlette"], + "terms": ["fastapi", "pydantic", "uvicorn", "starlette", "sse-starlette"], }, "sqlite": { "phrases": [ "sqlite", + "set up a sqlite database", "wal mode", "fts5", "full-text search", "better-sqlite3", "cloudflare d1", - "json1 extension", + "store json in sqlite", + "write ctes", + "window functions", ], - "terms": ["aiosqlite"], + "terms": ["aiosqlite", "better-sqlite3"], }, "claude-code-headless": { "phrases": [ @@ -49,31 +52,39 @@ "claude code headless", "run claude in ci", "claude in pipeline", + "parse stream-json output", + "track costs programmatically", + "permissions for scripts", ], - "terms": [], + "terms": ["--output-format stream-json", "--permission-mode"], }, "claude-agent-sdk": { "phrases": [ "agent sdk", "claude agent sdk", - "build an agent", - "create an agent", + "build an agent with the claude agent sdk", "canusetool", "sdk permissions", + "create mcp tools", + "define subagents", + "configure sdk hooks", + "stream sdk messages", ], - "terms": ["claude-agent-sdk", "claude_agent_sdk"], + "terms": ["claude-agent-sdk", "claude_agent_sdk", "createSdkMcpServer"], }, "pydantic-ai": { "phrases": [ "pydantic ai", "pydantic-ai", "pydanticai", - "ai agent", - "runcontext", - "vercel ai adapter", - "model fallback", + "build a pydanticai agent", + "add tools to an agent", + "stream responses with pydanticai", + "test a pydanticai agent", + "connect pydanticai to svelte", + "configure model fallbacks", ], - "terms": ["pydanticai"], + "terms": ["pydanticai", "RunContext", "VercelAIAdapter", "FallbackModel"], }, "testing": { "phrases": [ @@ -87,12 +98,11 @@ "mock dependencies", "test endpoint", "test component", + "test sse streaming", "unit test", "integration test", - "run tests", - "run the tests", ], - "terms": ["pytest", "vitest"], + "terms": ["pytest", "vitest", "pytest-anyio", "httpx AsyncClient"], }, "docker-py": { "phrases": [ @@ -102,8 +112,12 @@ "docker engine api", "docker from python", "docker api", + "manage docker containers from python", + "create containers programmatically", + "stream container logs", + "monitor container health from python", ], - "terms": ["aiodocker"], + "terms": ["aiodocker", "DockerClient"], }, "svelte5": { "phrases": [ @@ -113,12 +127,11 @@ "svelte rune", "svelte 5", "svelte5", - "layercake", - "layer cake", - "svelte-dnd-action", - "svelte dnd", + "migrate from svelte 4", + "manage state with $state", + "drag and drop to svelte", ], - "terms": ["sveltekit", "svelte"], + "terms": ["sveltekit", "svelte", "svelte-dnd-action", "@ai-sdk/svelte"], }, "docker": { "phrases": [ @@ -129,11 +142,10 @@ "multi-stage build", "health check", "healthcheck", - "docker network", - "docker volume", - "docker image", + "docker compose watch", + "optimize docker image", ], - "terms": ["dockerfile", "compose"], + "terms": ["dockerfile", "compose.yaml", "BuildKit"], }, "skill-building": { "phrases": [ @@ -144,6 +156,8 @@ "skill instructions", "skill authoring", "design a skill", + "improve a skill description", + "optimize skill content", ], "terms": [], }, @@ -151,49 +165,46 @@ "phrases": [ "debug logs", "check logs", + "check container logs", "find error", "investigate failure", - "container logs", "what went wrong", "why did this crash", "diagnose the issue", "look at the logs", "read the logs", + "read docker logs", "analyze error", ], - "terms": ["diagnose", "troubleshoot"], + "terms": ["diagnose", "troubleshoot", "OOMKilled", "ECONNREFUSED"], }, "refactoring-patterns": { "phrases": [ "refactor this", "clean up code", - "improve code structure", - "reduce complexity", - ], - "terms": [ - "refactor", - "refactoring", - "code smell", - "extract function", - "dead code", + "clean up this function", + "extract a method", + "fix code smells", + "reduce code duplication", + "simplify this class", + "break up this large function", + "remove dead code", ], + "terms": ["refactor", "refactoring", "code smell", "feature envy", "god class"], }, "security-checklist": { "phrases": [ "security review", + "security issues", + "security vulnerabilities", "check for vulnerabilities", + "scan for secrets", "audit security", - "find security issues", - ], - "terms": [ - "security", - "vulnerability", - "owasp", - "injection", - "xss", - "secrets", - "cve", + "review for injection", + "owasp compliance", + "hardcoded credentials", ], + "terms": ["owasp", "injection", "xss", "cve", "trivy", "gitleaks"], }, "git-forensics": { "phrases": [ @@ -201,62 +212,67 @@ "who changed this", "when did this break", "git blame", + "bisect a regression", + "recover a lost commit", + "search git history", + "find when code was removed", + "trace the history", + "use git reflog", ], - "terms": ["bisect", "blame", "archaeology", "git log", "pickaxe", "reflog"], + "terms": ["bisect", "blame", "pickaxe", "reflog", "git log -S"], }, "specification-writing": { "phrases": [ "write a spec", + "write requirements", "define requirements", "acceptance criteria", "user stories", + "use ears format", + "given/when/then", + "write given/when/then scenarios", + "structure requirements", ], - "terms": [ - "specification", - "requirements", - "ears", - "gherkin", - "given when then", - ], + "terms": ["specification", "ears", "gherkin", "given when then"], }, "performance-profiling": { "phrases": [ + "profile this code", "profile performance", "find bottleneck", + "find the bottleneck", "benchmark this", + "create a flamegraph", + "find memory leaks", "why is this slow", + "measure execution time", + "reduce latency", ], - "terms": [ - "profiling", - "benchmark", - "flamegraph", - "bottleneck", - "latency", - "throughput", - ], + "terms": ["cProfile", "py-spy", "scalene", "flamegraph", "hyperfine"], }, "api-design": { "phrases": [ "api design", "rest api design", "design an api", - "design a rest", - "api convention", - "endpoint design", + "design rest endpoints", "api versioning", - "pagination pattern", - "error response format", + "pagination strategy", + "design error responses", + "rate limiting", + "openapi documentation", ], - "terms": ["openapi", "swagger", "rfc7807"], + "terms": ["openapi", "swagger", "rfc7807", "rfc 7807"], }, "ast-grep-patterns": { "phrases": [ "ast-grep", "ast grep", "structural search", - "structural code search", "syntax-aware search", - "tree-sitter", + "find code patterns", + "search with ast-grep", + "use tree-sitter", ], "terms": ["sg run", "ast-grep", "tree-sitter"], }, @@ -269,6 +285,7 @@ "license check", "unused dependencies", "vulnerability scan", + "find unused dependencies", ], "terms": ["pip-audit", "npm audit", "cargo audit", "govulncheck"], }, @@ -279,10 +296,10 @@ "add docstrings", "add jsdoc", "document the api", - "documentation template", + "create architecture docs", "update the docs", ], - "terms": ["docstring", "jsdoc", "tsdoc", "godoc", "rustdoc"], + "terms": ["docstring", "jsdoc", "tsdoc", "rustdoc", "Sphinx"], }, "migration-patterns": { "phrases": [ @@ -293,8 +310,10 @@ "bump python", "upgrade pydantic", "migrate express", + "modernize the codebase", + "commonjs to esm", ], - "terms": ["migrate", "migration", "upgrade"], + "terms": ["migrate", "migration"], }, "spec-build": { "phrases": [ @@ -302,10 +321,9 @@ "build from spec", "start building", "spec-build", - "implement this feature from the spec", + "implement this feature", "build what the spec describes", - "implement from the spec", - "build the feature", + "run spec-build", ], "terms": ["spec-build"], }, @@ -317,9 +335,86 @@ "spec-review", "does code match spec", "audit implementation", + "run spec-review", + "regression check", ], "terms": ["spec-review"], }, + "spec-check": { + "phrases": [ + "check spec health", + "audit specs", + "which specs are stale", + "find missing specs", + "review spec quality", + "run spec-check", + "are my specs up to date", + ], + "terms": ["spec-check"], + }, + "spec-init": { + "phrases": [ + "initialize specs", + "specs directory", + "set up specs", + "bootstrap specs", + "start using specs", + "create spec directory", + "init specs", + "set up .specs", + ], + "terms": ["spec-init"], + }, + "spec-new": { + "phrases": [ + "create a spec", + "new spec", + "new feature spec", + "write a spec for", + "spec this feature", + "start a new spec", + "plan a feature", + "add a spec", + ], + "terms": ["spec-new"], + }, + "spec-refine": { + "phrases": [ + "refine the spec", + "review spec assumptions", + "validate spec decisions", + "approve the spec", + "walk me through the spec", + "check spec for assumptions", + "iterate on the spec", + ], + "terms": ["spec-refine"], + }, + "spec-update": { + "phrases": [ + "update the spec", + "mark spec as implemented", + "as-built update", + "finish the spec", + "close the spec", + "update spec status", + "sync spec with code", + ], + "terms": ["spec-update"], + }, + "team": { + "phrases": [ + "spawn a team", + "create a team", + "team of agents", + "use a swarm", + "work in parallel", + "coordinate multiple agents", + "split this across agents", + "team up", + ], + "terms": ["TeamCreate", "SendMessage"], + }, } # Pre-compile term patterns for whole-word matching @@ -370,25 +465,19 @@ def main() -> None: return skill_list = ", ".join(f'"{s}"' for s in skills) - is_subagent = "subagent_type" in data - if is_subagent: - output = { + output = { + "hookSpecificOutput": { + "hookEventName": "UserPromptSubmit", "additionalContext": ( - f"Available skills matching this planning task: {skill_list}. " - "These skills contain project-specific patterns, conventions, " - "and reference material. Consider their guidance when designing " - "the implementation approach." - ) - } - else: - output = { - "systemMessage": ( - f"The user's prompt matches available skill(s): " - f"{skill_list}. Load the relevant skill(s) using the Skill tool " - f"before responding." - ) + f"MANDATORY — Skill activation required. The user's prompt matches: {skill_list}. " + f"Before responding, evaluate each matched skill: is it relevant to this specific request? " + f"For each relevant skill, activate it using the Skill tool NOW. " + f"Skip any that are not relevant to the user's actual intent. " + f"Do not proceed with implementation until relevant skills are loaded." + ), } + } json.dump(output, sys.stdout) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/api-design/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/api-design/SKILL.md index f0633a2..41718ea 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/api-design/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/api-design/SKILL.md @@ -1,12 +1,15 @@ --- name: api-design description: >- - This skill should be used when the user asks to "design an API", - "design REST endpoints", "plan API versioning", "choose pagination strategy", - "design error responses", "API conventions", "endpoint design", - "create API documentation", or discusses REST API design, HTTP method - semantics, status code selection, authentication patterns, or rate limiting. -version: 0.1.0 + Provides REST API design guidance covering resource naming, pagination + strategies, error responses, versioning, and authentication patterns. USE + WHEN the user asks to "design an API", "design REST endpoints", "plan API + versioning", "choose a pagination strategy", "design error responses", + "set up rate limiting", "create OpenAPI documentation", or works with REST + conventions, HTTP method semantics, cursor pagination, RFC 7807, JWT auth, + status codes. DO NOT USE for API implementation code — use the fastapi skill + for building endpoints. +version: 0.2.0 --- # API Design diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/ast-grep-patterns/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/ast-grep-patterns/SKILL.md index d86ad0f..3a17128 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/ast-grep-patterns/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/ast-grep-patterns/SKILL.md @@ -1,12 +1,13 @@ --- name: ast-grep-patterns description: >- - This skill should be used when the user asks to "use ast-grep", - "structural search", "syntax-aware search", "find code patterns", - "search with ast-grep", "use tree-sitter", "find function calls structurally", - or discusses ast-grep patterns, structural code search, meta-variables, - tree-sitter parsing, or syntax-aware code matching. -version: 0.1.0 + Teaches syntax-aware code search using ast-grep (sg) and tree-sitter with + meta-variable patterns for functions, imports, and classes. USE WHEN the + user asks to "use ast-grep", "structural search", "find code patterns", + "search with ast-grep", "use tree-sitter", "syntax-aware search", or works + with sg run, $$$ARGS meta-variables, tree-sitter tags. DO NOT USE for + simple text searches where Grep suffices. +version: 0.2.0 --- # AST-Grep Patterns diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-agent-sdk/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-agent-sdk/SKILL.md index d766cf7..6236649 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-agent-sdk/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-agent-sdk/SKILL.md @@ -1,14 +1,14 @@ --- name: claude-agent-sdk description: >- - This skill should be used when the user asks to "build an agent with the Claude Agent SDK", - "use the Claude Agent SDK", "create an agent with TypeScript SDK", "configure SDK permissions", - "use canUseTool callback", "create custom MCP tools with createSdkMcpServer", - "manage SDK sessions", "define subagents", "configure SDK hooks", - "set up SDK sandbox", "stream SDK messages", "use sdk query function", - or discusses Claude Agent SDK TypeScript integration, SDK permission modes, - SDK message types, agent definitions, or programmatic Claude agent orchestration. -version: 0.1.0 + Provides Claude Agent SDK patterns in TypeScript covering query function, + permissions, MCP tools, subagents, and hooks. USE WHEN the user asks to + "build an agent with the Claude Agent SDK", "use canUseTool callback", + "create MCP tools with createSdkMcpServer", "define subagents", "configure + SDK hooks", "stream SDK messages", or works with @anthropic-ai/claude-agent-sdk, + query(), PermissionResult, AgentDefinition. DO NOT USE for PydanticAI Python + agents or Claude Code CLI headless mode. +version: 0.2.0 --- # Claude Agent SDK (TypeScript) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-code-headless/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-code-headless/SKILL.md index cd1a36a..d870e77 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-code-headless/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-code-headless/SKILL.md @@ -1,15 +1,14 @@ --- name: claude-code-headless description: >- - This skill should be used when the user asks to "run Claude Code in headless mode", - "use claude -p for automation", "parse stream-json output from Claude Code", - "use the Claude Agent SDK", "run Claude Code in CI/CD", - "configure MCP servers for headless Claude", - "set up Claude Code permissions for scripts", - "track Claude Code costs programmatically", or discusses Claude Code - print mode, non-interactive pipelines, SDK integration in TypeScript or Python, - structured output with json-schema, or session management for automation. -version: 0.1.0 + Guides non-interactive Claude Code usage via the -p flag, stream-json output + parsing, and CI/CD pipeline integration. USE WHEN the user asks to "run + Claude Code in headless mode", "use claude -p for automation", "parse + stream-json output", "run Claude Code in CI/CD", "track costs + programmatically", "set up permissions for scripts", or works with + --output-format stream-json, --permission-mode, --json-schema, --resume. + DO NOT USE for the TypeScript SDK API — use claude-agent-sdk instead. +version: 0.2.0 --- # Claude Code Headless diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/debugging/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/debugging/SKILL.md index 0688e3f..e660c67 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/debugging/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/debugging/SKILL.md @@ -1,13 +1,17 @@ --- name: debugging description: >- - This skill should be used when the user asks to "debug logs", "check logs", - "find error in logs", "read docker logs", "investigate failure", - "check container logs", "analyze error output", "find what went wrong", - "why did this crash", "check what happened", "diagnose the issue", - "look at the logs", or discusses log analysis, container debugging, - error investigation, crash diagnosis, or service failure troubleshooting. -version: 0.1.0 + Guides systematic log analysis and error diagnosis across Docker, systemd, + and application environments using forensic investigation methodology. + USE WHEN the user asks to "debug logs", "check container logs", + "why did this crash", "investigate failure", "find error in logs", + "read docker logs", "diagnose the issue", or "analyze error output", + or works with Docker exit codes, Python tracebacks, ECONNREFUSED, + OOMKilled, or journalctl. DO NOT USE for performance profiling, + security auditing, or dependency vulnerability scanning. +version: 0.2.0 +allowed-tools: Bash, Read, Glob, Grep +argument-hint: "[service or log-path]" --- # Debugging & Log Analysis diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/dependency-management/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/dependency-management/SKILL.md index 2e677c3..cb29001 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/dependency-management/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/dependency-management/SKILL.md @@ -1,12 +1,16 @@ --- name: dependency-management description: >- - This skill should be used when the user asks to "check dependencies", - "audit dependencies", "find outdated packages", "check dependency health", - "scan for vulnerabilities", "find unused dependencies", "license check", - "npm audit", "pip audit", "cargo audit", or discusses dependency analysis, - supply chain security, package version gaps, or license compliance. -version: 0.1.0 + Provides a five-phase dependency health analysis covering outdated packages, + security vulnerabilities, unused deps, version conflicts, and license + compliance across npm, pip, cargo, and Go modules. USE WHEN the user asks + to "audit dependencies", "find outdated packages", "find unused + dependencies", "check dependency health", "license check", "npm audit", + "pip-audit", or "cargo audit", or works with supply chain security, CVSS + scores, or SPDX identifiers. DO NOT USE for general security code review + or application-level vulnerability scanning. +version: 0.2.0 +allowed-tools: Bash, Read, Glob, Grep --- # Dependency Management diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker-py/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker-py/SKILL.md index f757926..bfc402d 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker-py/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker-py/SKILL.md @@ -1,13 +1,15 @@ --- name: docker-py description: >- - This skill should be used when the user asks to "manage Docker containers from Python", - "create containers programmatically", "stream Docker container logs", - "execute commands in a running container", "manage Docker volumes from code", - "build images with the Docker SDK", "use docker-py for container lifecycle", - "monitor container health from Python", or discusses docker-py, - aiodocker, programmatic container management, or Docker Engine API. -version: 0.1.0 + Provides patterns for programmatic Docker container management using the + Docker SDK for Python and aiodocker. USE WHEN the user asks to "manage Docker + containers from Python", "create containers programmatically", "stream + container logs", "execute commands in a running container", "build images + with docker-py", "monitor container health from Python", or works with + docker-py, aiodocker, DockerClient, Docker Engine API, container lifecycle. + DO NOT USE for writing Dockerfiles or Docker Compose files — use the docker + skill instead. +version: 0.2.0 --- # Docker SDK for Python diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker/SKILL.md index 521451a..442ea51 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker/SKILL.md @@ -1,14 +1,14 @@ --- name: docker description: >- - This skill should be used when the user asks to "write a Dockerfile", - "set up Docker Compose", "create a multi-stage Docker build", - "add health checks to Docker Compose", "use Docker Compose watch for development", - "configure Docker networking", "optimize Docker image size", - "add secrets to Docker Compose", or discusses Dockerfile best practices, - Compose service orchestration, container networking, volume management, - build caching, resource limits, or development workflows with containers. -version: 0.1.0 + Guides Dockerfile authoring and Docker Compose orchestration with multi-stage + builds, health checks, and dev watch mode. USE WHEN the user asks to "write + a Dockerfile", "set up Docker Compose", "create a multi-stage build", "add + health checks", "use Docker Compose watch", "optimize Docker image size", + or works with compose.yaml, docker compose, BuildKit, Compose profiles. + DO NOT USE for programmatic container management from Python — use + docker-py instead. +version: 0.2.0 --- # Docker & Docker Compose diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/documentation-patterns/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/documentation-patterns/SKILL.md index 95522bf..c774b44 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/documentation-patterns/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/documentation-patterns/SKILL.md @@ -1,12 +1,13 @@ --- name: documentation-patterns description: >- - This skill should be used when the user asks to "write a README", - "write documentation", "add docstrings", "add JSDoc", "document the API", - "create architecture docs", "documentation template", "update the docs", - or discusses docstring formats, README structure, API documentation, - inline comments, or technical writing patterns. -version: 0.1.0 + Guides documentation authoring including README structure, docstring formats, + API references, and architecture docs. USE WHEN the user asks to "write a + README", "add docstrings", "add JSDoc", "document the API", "create + architecture docs", "write documentation", "update the docs", or works with + Google-style docstrings, Sphinx, rustdoc, TSDoc, OpenAPI annotations. + DO NOT USE for writing code, fixing bugs, or generating changelogs. +version: 0.2.0 --- # Documentation Patterns diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/fastapi/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/fastapi/SKILL.md index 1bce0b7..1ae1af1 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/fastapi/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/fastapi/SKILL.md @@ -1,14 +1,15 @@ --- name: fastapi description: >- - This skill should be used when the user asks to "build a FastAPI app", - "create a REST API with FastAPI", "add SSE streaming to FastAPI", - "use dependency injection in FastAPI", "define Pydantic models for an API", - "stream LLM responses with FastAPI", "add middleware to FastAPI", - "handle background tasks in FastAPI", or discusses FastAPI routing, - Pydantic v2 models, dependency injection, server-sent events, - or ASGI middleware. -version: 0.1.0 + Teaches modern FastAPI development including REST APIs, Pydantic v2 models, + SSE streaming, and ASGI middleware patterns. USE WHEN the user asks to "build + a FastAPI app", "create a REST API with FastAPI", "add SSE streaming", "use + dependency injection in FastAPI", "define Pydantic models", "stream LLM + responses", "add middleware to FastAPI", or works with FastAPI routing, + Pydantic v2, sse-starlette, EventSourceResponse, APIRouter, BackgroundTasks. + DO NOT USE for general Python web frameworks like Flask or Django, or for + frontend development. +version: 0.2.0 --- # FastAPI Development diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/git-forensics/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/git-forensics/SKILL.md index 54fbdf7..53013f1 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/git-forensics/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/git-forensics/SKILL.md @@ -1,14 +1,16 @@ --- name: git-forensics description: >- - This skill should be used when the user asks to "find who changed this line", - "search git history for a deleted function", "bisect a regression", - "recover a lost commit", "investigate when a bug was introduced", - "trace the history of a file", "search commit messages", - "find when code was removed", "check git blame", "use git reflog", - or discusses git archaeology, git bisect, git log search, pickaxe, - blame analysis, reflog recovery, or commit history investigation. -version: 0.1.0 + Provides git history investigation techniques including blame analysis, + bisect workflows, pickaxe search, and reflog recovery for tracing code + changes and recovering lost work. USE WHEN the user asks to "find who + changed this line", "bisect a regression", "recover a lost commit", + "search git history", "find when code was removed", "check git blame", + "use git reflog", or "trace the history of a file", or works with git + log -S, git bisect run, or .git-blame-ignore-revs. DO NOT USE for + routine git operations like committing, branching, or merging. +version: 0.2.0 +allowed-tools: Bash, Read, Grep --- # Git Forensics @@ -103,7 +105,7 @@ Track a file across renames. Without `--follow`, history stops at the rename: # Follow a file through renames git log --follow --oneline -- path/to/current_name.py -# Blame through renames +# Show patch history through renames git log --follow -p -- path/to/file.py ``` diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/migration-patterns/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/migration-patterns/SKILL.md index 632680c..96df4b3 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/migration-patterns/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/migration-patterns/SKILL.md @@ -1,12 +1,13 @@ --- name: migration-patterns description: >- - This skill should be used when the user asks to "migrate from X to Y", - "upgrade to version N", "bump Python version", "upgrade pydantic", - "migrate express to fastify", "framework migration", "version upgrade", - "modernize the codebase", or discusses code migration, framework upgrades, - API version bumps, or dependency migration strategies. -version: 0.1.0 + Guides incremental, rollback-safe framework upgrades and dependency + migrations with step-by-step verification. USE WHEN the user asks to + "migrate from X to Y", "upgrade to version N", "bump Python version", + "upgrade pydantic", "migrate express to fastify", "modernize the codebase", + or works with Pydantic v1-to-v2, Django upgrades, CommonJS to ESM. + DO NOT USE for routine dependency updates without API changes. +version: 0.2.0 --- # Migration Patterns diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/performance-profiling/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/performance-profiling/SKILL.md index 7452703..5a4cd75 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/performance-profiling/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/performance-profiling/SKILL.md @@ -1,14 +1,16 @@ --- name: performance-profiling description: >- - This skill should be used when the user asks to "profile this code", - "find the bottleneck", "optimize performance", "measure execution time", - "check memory usage", "create a flamegraph", "benchmark this function", - "find memory leaks", "reduce latency", "run a performance test", - or discusses profiling tools, flamegraphs, benchmarking methodology, - cProfile, py-spy, scalene, Chrome DevTools performance, - memory profiling, or hot path analysis. -version: 0.1.0 + Guides measure-first performance investigation using CPU profilers, memory + analyzers, flamegraphs, and reproducible benchmarking across Python and + Node.js. USE WHEN the user asks to "profile this code", "find the + bottleneck", "create a flamegraph", "benchmark this function", "find + memory leaks", "check memory usage", "reduce latency", or "measure + execution time", or works with cProfile, py-spy, scalene, clinic.js, + Chrome DevTools, hyperfine, or pytest-benchmark. DO NOT USE for security + auditing, dependency management, or code refactoring. +version: 0.2.0 +allowed-tools: Bash, Read, Glob, Grep --- # Performance Profiling diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/pydantic-ai/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/pydantic-ai/SKILL.md index 1dc4ce5..388219b 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/pydantic-ai/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/pydantic-ai/SKILL.md @@ -1,13 +1,14 @@ --- name: pydantic-ai description: >- - This skill should be used when the user asks to "build a PydanticAI agent", - "create an AI agent with PydanticAI", "add tools to a PydanticAI agent", - "stream responses with PydanticAI", "test a PydanticAI agent", - "connect PydanticAI to a Svelte frontend", "use RunContext for dependency injection", - "configure model fallbacks in PydanticAI", or discusses PydanticAI agents, - tool decorators, structured output, agent testing, or VercelAIAdapter. -version: 0.1.0 + Teaches PydanticAI agent development with tool decorators, RunContext + dependency injection, streaming, and VercelAIAdapter. USE WHEN the user + asks to "build a PydanticAI agent", "add tools to an agent", "stream + responses with PydanticAI", "test a PydanticAI agent", "connect PydanticAI + to Svelte", "configure model fallbacks", or works with pydantic-ai, Agent, + RunContext, TestModel, FallbackModel, VercelAIAdapter. DO NOT USE for Claude + Agent SDK TypeScript agents or general LLM API calls. +version: 0.2.0 --- # PydanticAI Agent Development diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/refactoring-patterns/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/refactoring-patterns/SKILL.md index 835fcf3..95a7d55 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/refactoring-patterns/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/refactoring-patterns/SKILL.md @@ -1,14 +1,15 @@ --- name: refactoring-patterns description: >- - This skill should be used when the user asks to "refactor this code", - "clean up this function", "extract a method", "reduce code duplication", - "fix code smells", "simplify this class", "break up this large function", - "apply design patterns", "remove dead code", "improve code structure", - or discusses code smells, refactoring techniques, extract function, - inline variable, feature envy, god class, or behavior-preserving - transformations. -version: 0.1.0 + Teaches behavior-preserving code transformations with a smell-detect, + transform, verify cycle and language-specific idioms for Python and + TypeScript. USE WHEN the user asks to "refactor this code", "extract a + method", "fix code smells", "reduce code duplication", "simplify this + class", "break up this large function", "clean up this function", or + "remove dead code", or works with god class, feature envy, data clump, + primitive obsession, or inline variable. DO NOT USE for adding new + features, fixing bugs, or performance optimization. +version: 0.2.0 --- # Refactoring Patterns diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/security-checklist/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/security-checklist/SKILL.md index 6bdb9bd..3f9432c 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/security-checklist/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/security-checklist/SKILL.md @@ -1,14 +1,15 @@ --- name: security-checklist description: >- - This skill should be used when the user asks to "check for security issues", - "audit this code for vulnerabilities", "scan for secrets", "review for - injection attacks", "check OWASP compliance", "find security bugs", - "detect hardcoded credentials", "review authentication logic", - "check for XSS", "audit dependencies for vulnerabilities", - or discusses security review, vulnerability scanning, OWASP Top 10, - secrets detection, SQL injection, command injection, or dependency auditing. -version: 0.1.0 + Provides defense-in-depth security review covering OWASP Top 10, secrets + detection, and dependency CVE scanning. USE WHEN the user asks to "check + for security issues", "scan for secrets", "audit dependencies for + vulnerabilities", "review for injection attacks", "check OWASP compliance", + "detect hardcoded credentials", or works with SQL injection, command + injection, pip-audit, npm audit, trivy, gitleaks. DO NOT USE for performance + profiling or general code quality reviews. +version: 0.2.0 +allowed-tools: Bash, Read, Glob, Grep --- # Security Checklist diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/skill-building/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/skill-building/SKILL.md index 2048702..4847f9f 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/skill-building/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/skill-building/SKILL.md @@ -1,13 +1,13 @@ --- name: skill-building description: >- - This skill should be used when the user asks to "build a skill", "write a - SKILL.md", "create a Claude Code skill", "design skill instructions", - "improve a skill description", "optimize skill content", "write effective - prompts for skills", or discusses skill authoring best practices, progressive - disclosure, or cross-vendor prompt engineering principles for Claude Code - plugins. -version: 0.1.0 + Guides Claude Code plugin skill creation covering SKILL.md structure, + description optimization, and progressive disclosure. USE WHEN the user + asks to "build a skill", "write a SKILL.md", "create a Claude Code skill", + "improve a skill description", "optimize skill content", "design skill + instructions", or works with skill authoring patterns or plugin directory + structure. DO NOT USE for application code or general prompt engineering. +version: 0.2.0 --- # Skill Building for Claude Code Plugins diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/sqlite/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/sqlite/SKILL.md index 575d22e..afda50a 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/sqlite/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/sqlite/SKILL.md @@ -1,13 +1,15 @@ --- name: sqlite description: >- - This skill should be used when the user asks to "set up a SQLite database", - "use WAL mode in SQLite", "query SQLite with Python", "use better-sqlite3", - "add full-text search with FTS5", "store JSON in SQLite", - "use SQLite with Cloudflare D1", "write CTEs or window functions in SQLite", - or discusses SQLite pragmas, schema design, JSON1 extension, FTS5, - aiosqlite, or embedded database patterns. -version: 0.1.0 + Teaches SQLite development including WAL mode, FTS5 full-text search, JSON1 + queries, and async Python integration with aiosqlite. USE WHEN the user asks + to "set up a SQLite database", "use WAL mode", "add full-text search with + FTS5", "store JSON in SQLite", "query SQLite with Python", "use + better-sqlite3", "use Cloudflare D1", "write CTEs or window functions", or + works with aiosqlite, better-sqlite3, PRAGMA configuration, STRICT tables, + expression indexes. DO NOT USE for PostgreSQL, MySQL, or other client-server + database systems. +version: 0.2.0 --- # SQLite Development diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/svelte5/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/svelte5/SKILL.md index debe7f8..cbdfa30 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/svelte5/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/svelte5/SKILL.md @@ -1,14 +1,13 @@ --- name: svelte5 description: >- - This skill should be used when the user asks to "build a Svelte component", - "create a Svelte app", "use Svelte runes", "set up a SvelteKit SPA", - "migrate from Svelte 4 to Svelte 5", "manage state with runes", - "add reactivity in Svelte", "use AI SDK with Svelte", - "add drag and drop to Svelte", "build charts with LayerCake", - or discusses Svelte 5 component patterns, snippets, $state, $derived, - $effect, $props, or SvelteKit routing. -version: 0.1.0 + Guides Svelte 5 development with runes, SvelteKit SPA configuration, and + component architecture. USE WHEN the user asks to "build a Svelte component", + "use Svelte 5 runes", "set up a SvelteKit SPA", "migrate from Svelte 4 + to 5", "manage state with $state", "add drag and drop to Svelte", or works + with $state, $derived, $effect, $props, @ai-sdk/svelte, svelte-dnd-action. + DO NOT USE for Svelte 4 legacy codebases or React/Vue development. +version: 0.2.0 --- # Svelte 5 Development diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/team/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/team/SKILL.md index 4a82e96..2a06aba 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/team/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/team/SKILL.md @@ -1,11 +1,17 @@ --- name: team description: >- - This skill should be used when the user asks to "spawn a team", - "create a team of agents", "use a swarm", "work in parallel with agents", - "team up agents", "coordinate multiple agents", "split this across agents", - or needs to orchestrate parallel agent work using Claude Code Teams. -version: 0.1.0 + Guides agent team orchestration with TeamCreate, parallel teammate + spawning, task coordination, specialist agent selection, and + --teammate-mode configuration for concurrent workstreams. USE WHEN + the user asks to "spawn a team", "create a team of agents", "use a + swarm", "work in parallel", "coordinate multiple agents", "split this + across agents", "team up", or works with TeamCreate, SendMessage, and + multi-agent workflows. DO NOT USE for single-agent sequential tasks + where parallelism adds no value — a team requires 3+ independent + workstreams. +version: 0.2.0 +disable-model-invocation: true --- # Agent Team Orchestration @@ -113,6 +119,31 @@ TaskUpdate: - **Direct message:** `SendMessage` with `type: "message"` and `recipient: "test-writer"` - **Broadcast:** `SendMessage` with `type: "broadcast"` — use ONLY for critical team-wide issues - **Idle is normal:** Teammates go idle after each turn. This is expected. Send a message to wake them. +- **Quality gate hooks:** TeammateIdle and TaskCompleted hooks run automatically. TeammateIdle checks for incomplete tasks (exit 2 → teammate keeps working); TaskCompleted runs the test suite (exit 2 → task stays open). See agent-system plugin hooks. + +**In-process mode keyboard shortcuts:** + +| Shortcut | Action | +|----------|--------| +| `Shift+Down` | Cycle through teammates | +| `Ctrl+T` | Toggle task list | +| `Enter` | View a teammate's session | +| `Escape` | Interrupt teammate's current turn | + +> **Tip:** Use `claude --teammate-mode in-process` for per-session display mode override. Configure permanently via `teammateMode` in settings.json. + +### 5a. Plan Approval + +When `CLAUDE_CODE_PLAN_MODE_REQUIRED` is `true` (current setting), teammates run in read-only plan mode until the lead approves their plan. + +**Workflow:** +1. Teammate enters plan mode → creates an implementation plan +2. Lead receives `plan_approval_request` message with the plan +3. Lead reviews the plan and sends `plan_approval_response` (approve or reject) +4. On approval → teammate exits plan mode and implements +5. On rejection → teammate stays in plan mode, revises, resubmits + +**Influencing plans:** Include criteria in the spawn `prompt` to shape what the lead should look for (e.g., "only approve plans that include test coverage", "reject plans that modify shared utilities without coordination"). ### 6. Shutdown @@ -151,6 +182,18 @@ Prefix with `agent-system:` when spawning (e.g., `agent-system:test-writer`). --- +## Use Cases + +**Parallel code review** — split review criteria into independent domains (security, performance, test coverage). Each reviewer focuses on one lens, reducing blind spots. + +**Competing hypotheses** — adversarial investigation where teammates explore different theories about a bug or design decision. Each builds evidence for their hypothesis; lead synthesizes findings. + +**Cross-layer coordination** — frontend, backend, and tests each owned by a different teammate. Clear file ownership prevents conflicts; integration points are managed by the lead. + +**Research sweep** — parallel investigation of libraries, APIs, or approaches. Each researcher covers one option; lead compares findings and makes the selection. + +--- + ## Team Composition Examples | Purpose | Recommended Team | @@ -180,6 +223,29 @@ Prefix with `agent-system:` when spawning (e.g., `agent-system:test-writer`). --- +## Best Practices + +- **Give teammates enough context** — they don't inherit conversation history. The spawn `prompt` must be self-contained: include file paths, requirements, constraints, and project conventions. +- **Size tasks appropriately** — too small = coordination overhead exceeds benefit; too large = work too long without check-ins. Aim for self-contained units producing clear deliverables, roughly 5-6 tasks per teammate. +- **Wait for teammates to finish** — leads sometimes start implementing work that teammates are handling. If you notice this, redirect yourself to monitoring and coordination. +- **Start with research and review** — for first-time team use, prefer tasks with clear boundaries that don't require code changes: reviewing PRs, researching libraries, investigating bugs. +- **Monitor and steer** — check progress via `TaskList`, redirect failing approaches, synthesize findings. Unattended teams risk wasted effort. +- **Avoid file conflicts** — break work so each teammate owns different files. Agents with `isolation: worktree` (test-writer, refactorer, doc-writer, migrator) get automatic file isolation via git worktrees. + +--- + +## Limitations + +- **No session resumption** — `/resume` does not restore in-process teammates. Plan team work to complete in one session. +- **Task status can lag** — teammates sometimes fail to mark tasks complete. Use `TaskList` to verify and `SendMessage` to prompt updates. +- **One team per session** — clean up the current team (`TeamDelete`) before starting a new one. +- **No nested teams** — teammates cannot create teams (TeamCreate/TeamDelete are disallowed for team members). +- **Lead is fixed** — leadership cannot be promoted or transferred during a session. +- **Permissions set at spawn** — all teammates inherit the lead's permission mode at spawn time. +- **Split panes require tmux or iTerm2** — in-process mode uses the terminal; external split-pane workflows need tmux or iTerm2 with `it2` CLI. + +--- + ## Tool Reference | Tool | Purpose | Key Parameters | diff --git a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/testing/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/testing/SKILL.md index 5aed693..9ab019f 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/testing/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/testing/SKILL.md @@ -1,13 +1,16 @@ --- name: testing description: >- - This skill should be used when the user asks to "write tests for a FastAPI endpoint", - "test a Svelte component", "set up pytest fixtures for FastAPI", - "configure Vitest for SvelteKit", "mock dependencies in FastAPI tests", - "test SSE streaming endpoints", "write component tests with Testing Library", - "set up database fixtures for API tests", or discusses pytest, httpx AsyncClient, - Vitest, @testing-library/svelte, dependency overrides, or test fixtures. -version: 0.1.0 + Provides testing patterns for FastAPI endpoints and Svelte 5 components + using pytest and Vitest. USE WHEN the user asks to "write tests for a + FastAPI endpoint", "test a Svelte component", "set up pytest fixtures", + "configure Vitest for SvelteKit", "mock dependencies in tests", "test SSE + streaming endpoints", or works with pytest, httpx AsyncClient, Vitest, + @testing-library/svelte, MSW, pytest-anyio. DO NOT USE for general testing + theory unrelated to FastAPI or Svelte. +version: 0.2.0 +allowed-tools: Bash, Read, Write, Edit, Glob, Grep +argument-hint: "[file or module]" --- # Testing (FastAPI + Svelte) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/.claude-plugin/plugin.json b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/.claude-plugin/plugin.json index c53f501..ad3e896 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/.claude-plugin/plugin.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/.claude-plugin/plugin.json @@ -1,7 +1,6 @@ { "name": "spec-workflow", "description": "Specification lifecycle management: creation, refinement, building, reviewing, updating, and auditing", - "version": "1.0.0", "author": { "name": "AnExiledDev" } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/README.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/README.md new file mode 100644 index 0000000..deadbd1 --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/README.md @@ -0,0 +1,192 @@ +# spec-workflow + +Claude Code plugin that manages the full specification lifecycle: creating, refining, building, reviewing, updating, and auditing feature specs. Includes an advisory hook that reminds about spec updates when code changes but specs don't. + +## What It Does + +Two capabilities: + +1. **Spec lifecycle skills** — 8 skills that cover the complete journey from bootstrapping a `.specs/` directory to closing out an as-built spec after implementation. + +2. **Spec reminder hook** — A `Stop` hook that fires when source code was modified but no `.specs/` files were updated, advising Claude to run `/spec-update`. + +### Skill Catalog + +| Skill | Slash Command | Purpose | +|-------|---------------|---------| +| spec-init | `/spec-init` | Bootstrap `.specs/` directory with BACKLOG.md, MILESTONES.md, ROADMAP.md | +| spec-new | `/spec-new` | Create a new feature spec from EARS template | +| spec-refine | `/spec-refine` | Validate assumptions with user, upgrade requirements to `[user-approved]` | +| spec-build | `/spec-build` | Orchestrate full implementation: plan, build, review, close | +| spec-check | `/spec-check` | Audit all specs for health issues | +| spec-review | `/spec-review` | Verify implementation against a spec | +| spec-update | `/spec-update` | As-built closure: update spec to match implementation | +| specification-writing | `/skill specification-writing` | Domain knowledge for writing high-quality specs | + +### Spec Lifecycle + +``` +/spec-init Bootstrap .specs/ directory + | +/spec-new Create feature spec (draft, [assumed] requirements) + | +/spec-refine Validate with user -> [user-approved] requirements + | +/spec-build 5-phase implementation orchestration: + | Phase 1: Discovery + | Phase 2: Planning + | Phase 3: Building ([ ] -> [~]) + | Phase 4: Review ([~] -> [x]) + | Phase 5: Closure (as-built update) + | +/spec-review Standalone verification (post-change audits) + | +/spec-update Manual as-built closure + | +/spec-check Health audit across all specs +``` + +### Acceptance Criteria Markers + +| Marker | Meaning | +|--------|---------| +| `[ ]` | Not started | +| `[~]` | Implemented, not yet verified | +| `[x]` | Verified — tests pass, behavior confirmed | + +### Approval and Requirement Tags + +- `**Approval:** draft` — Spec is in draft, not ready for implementation +- `**Approval:** user-approved` — Spec reviewed and approved by user +- `[assumed]` — Requirement inferred by Claude, needs validation +- `[user-approved]` — Requirement explicitly approved by user + +## How It Works + +### Hook Lifecycle + +``` +Claude stops responding (Stop event) + | + +-> Stop fires + | + +-> spec-reminder.py + | + +-> .specs/ directory exists? + | | + | +-> No -> Silent exit (no output) + | +-> Yes -> Continue + | + +-> Source code modified this session? + | | + | +-> No -> Silent exit + | +-> Yes -> Continue + | + +-> .specs/ files also modified? + | + +-> Yes -> Silent exit (already updated) + +-> No -> Inject advisory: "Run /spec-update" +``` + +### Monitored Source Directories + +The spec reminder watches for changes in these directories: + +`src/`, `lib/`, `app/`, `pkg/`, `internal/`, `cmd/`, `tests/`, `api/`, `frontend/`, `backend/`, `packages/`, `services/`, `components/`, `pages/`, `routes/` + +### Exit Code Behavior + +| Exit Code | Meaning | +|-----------|---------| +| 0 | Advisory injected (or silent — no action needed) | + +The hook never blocks operations. + +### Error Handling + +| Scenario | Behavior | +|----------|----------| +| No `.specs/` directory | Silent exit | +| Not a git repository | Silent exit | +| JSON parse failure | Silent exit | + +### Timeouts + +| Hook | Timeout | +|------|---------| +| Spec reminder (Stop) | 8s | + +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "spec-workflow@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + +## Plugin Structure + +``` +spec-workflow/ ++-- .claude-plugin/ +| +-- plugin.json # Plugin metadata ++-- hooks/ +| +-- hooks.json # Stop hook registration ++-- scripts/ +| +-- spec-reminder.py # Spec update advisory (Stop) ++-- skills/ +| +-- spec-init/ # Bootstrap .specs/ directory +| | +-- SKILL.md +| | +-- references/ +| | +-- backlog-template.md +| | +-- milestones-template.md +| | +-- roadmap-template.md +| +-- spec-new/ # Create new feature spec +| | +-- SKILL.md +| | +-- references/ +| | +-- template.md +| +-- spec-refine/ # Validate assumptions with user +| | +-- SKILL.md +| +-- spec-build/ # Full implementation orchestration +| | +-- SKILL.md +| | +-- references/ +| | +-- review-checklist.md +| +-- spec-check/ # Spec health audit +| | +-- SKILL.md +| +-- spec-review/ # Implementation verification +| | +-- SKILL.md +| +-- spec-update/ # As-built closure +| | +-- SKILL.md +| +-- specification-writing/ # Domain knowledge skill +| +-- SKILL.md +| +-- references/ +| +-- criteria-patterns.md +| +-- ears-templates.md ++-- README.md # This file +``` + +## Requirements + +- Python 3.11+ +- Git (for detecting file changes) +- Claude Code with plugin hook support (skills) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/hooks/hooks.json index 951d68f..9fb5dde 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/hooks/hooks.json @@ -3,7 +3,6 @@ "hooks": { "Stop": [ { - "matcher": "", "hooks": [ { "type": "command", diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/scripts/spec-reminder.py b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/scripts/spec-reminder.py index fcfd048..e1cd210 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/scripts/spec-reminder.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/scripts/spec-reminder.py @@ -9,7 +9,8 @@ Only fires when a .specs/ directory exists (project uses the spec system). Reads hook input from stdin (JSON). Returns JSON on stdout. -Always exits 0 (advisory, never blocking). +Blocks with decision/reason so Claude addresses the spec gap +before finishing. The stop_hook_active guard prevents infinite loops. """ import json @@ -115,7 +116,7 @@ def main(): "or /spec-refine if the spec is still in draft status." ) - json.dump({"additionalContext": message}, sys.stdout) + json.dump({"decision": "block", "reason": message}, sys.stdout) sys.exit(0) diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-build/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-build/SKILL.md index 0a8a7df..08be6c7 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-build/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-build/SKILL.md @@ -1,12 +1,15 @@ --- name: spec-build description: >- - This skill should be used when the user asks to "implement the spec", - "build from spec", "start building the feature", "spec-build", - "implement this feature from the spec", "build what the spec describes", - or needs to orchestrate full implementation of an approved specification - through a phased workflow of planning, building, reviewing, and closing. -version: 0.1.0 + Orchestrates full implementation of an approved specification through + 5 phases: discovery, planning, building, review, and closure. USE WHEN + the user asks to "implement the spec", "build from spec", "start building + the feature", "implement this feature", "build what the spec describes", + "run spec-build", or works with phased implementation workflows. + DO NOT USE for creating, refining, or updating specs — use spec-new, + spec-refine, or spec-update instead. +version: 0.2.0 +argument-hint: "[spec-path]" --- # Spec-Driven Implementation diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-check/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-check/SKILL.md index 634e008..def3afc 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-check/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-check/SKILL.md @@ -1,11 +1,16 @@ --- name: spec-check description: >- - This skill should be used when the user asks to "check spec status", - "audit specs", "which specs are stale", "spec health", "find missing - specs", "review spec quality", or needs a comprehensive audit of all - specifications in the project. -version: 0.1.0 + Audits all specifications in a project for health issues including stale + status, missing sections, unapproved drafts, and assumed requirements. + USE WHEN the user asks to "check spec health", "audit specs", "which + specs are stale", "find missing specs", "review spec quality", + "run spec-check", "are my specs up to date", or works with .specs/ + directory maintenance and specification metadata. + DO NOT USE for single-spec code review or implementation verification + — use spec-review for deep code-level audits against one spec. +version: 0.2.0 +argument-hint: "[domain or path]" context: fork agent: explorer --- diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-init/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-init/SKILL.md index 2b52209..85e445b 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-init/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-init/SKILL.md @@ -1,10 +1,14 @@ --- name: spec-init description: >- - This skill should be used when the user asks to "initialize specs", - "set up specs", "bootstrap specs", "start using specs", "create spec - directory", "init specs for this project", or needs to set up the - .specs/ directory structure for a project that doesn't have one yet. + Bootstraps the .specs/ directory structure for a project, creating + MILESTONES.md and BACKLOG.md from starter templates so spec-new has + a home. USE WHEN the user asks to "initialize specs", "set up specs", + "bootstrap specs", "start using specs", "create spec directory", + "init specs for this project", "set up .specs", or works with first- + time specification setup and project onboarding. + DO NOT USE if .specs/ already exists — use spec-check to audit health + or spec-new to add individual specs. version: 0.2.0 --- diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-new/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-new/SKILL.md index 58a615b..18bd574 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-new/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-new/SKILL.md @@ -1,11 +1,15 @@ --- name: spec-new description: >- - This skill should be used when the user asks to "create a spec", - "new feature spec", "write a spec for", "spec this feature", - "start a new spec", "plan a feature", or needs to create a new - specification file from the standard template. + Creates a new feature specification from the standard EARS template + with domain inference, acceptance criteria, and requirement tagging. + USE WHEN the user asks to "create a spec", "new feature spec", "write + a spec for", "spec this feature", "start a new spec", "plan a feature", + "add a spec", or works with .specs/ directory and feature planning. + DO NOT USE for updating existing specs after implementation — use + spec-update instead. Not for refining draft specs — use spec-refine. version: 0.2.0 +argument-hint: "[feature-name] [domain]" --- # Create New Feature Specification diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-refine/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-refine/SKILL.md index 006d01c..7c7caa1 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-refine/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-refine/SKILL.md @@ -1,13 +1,16 @@ --- name: spec-refine description: >- - This skill should be used when the user asks to "refine a spec", - "review spec assumptions", "validate spec decisions", "question the - spec", "iterate on the spec", "check spec for assumptions", "approve - the spec", "walk me through the spec", or needs iterative - user-driven refinement of a specification through structured - questioning rounds. -version: 0.1.0 + Guides iterative user-driven spec refinement through structured + questioning rounds that validate assumptions, tech decisions, and scope + boundaries. USE WHEN the user asks to "refine the spec", "review spec + assumptions", "validate spec decisions", "approve the spec", "walk me + through the spec", "check spec for assumptions", "iterate on the spec", + or works with [assumed] requirements needing user-approved upgrade. + DO NOT USE for creating new specs (use spec-new) or for post- + implementation updates (use spec-update). +version: 0.2.0 +argument-hint: "[spec-path]" --- # Iterative Spec Refinement diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-review/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-review/SKILL.md index 660d6d2..1ddbf89 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-review/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-review/SKILL.md @@ -1,12 +1,16 @@ --- name: spec-review description: >- - This skill should be used when the user asks to "review the spec", - "check spec adherence", "verify implementation", "spec-review", - "does code match spec", "audit implementation", or needs a standalone - deep implementation review that reads the code and confirms full - adherence to a specification. -version: 0.1.0 + Performs a standalone deep implementation review by reading code and + verifying full adherence to a specification's requirements and acceptance + criteria. USE WHEN the user asks to "review the spec", "verify + implementation", "does code match spec", "audit implementation", + "check spec adherence", "run spec-review", "regression check", or + works with post-implementation verification and pre-release audits. + DO NOT USE for batch metadata audits across all specs (use spec-check) + or for updating spec status after review (use spec-update). +version: 0.2.0 +argument-hint: "[spec-path]" --- # Spec Implementation Review diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-update/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-update/SKILL.md index 4ee756b..884a254 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-update/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-update/SKILL.md @@ -1,11 +1,16 @@ --- name: spec-update description: >- - This skill should be used when the user asks to "update the spec", - "mark spec as implemented", "as-built update", "spec maintenance", - "update spec status", "finish the spec", or after implementing a - feature when the spec needs to reflect what was actually built. -version: 0.1.0 + Performs the as-built spec update after implementation, closing the loop + between what was planned and what was built by setting status, checking + off acceptance criteria, and adding implementation notes. USE WHEN the + user asks to "update the spec", "mark spec as implemented", "as-built + update", "finish the spec", "close the spec", "update spec status", + "sync spec with code", or works with post-implementation documentation. + DO NOT USE for verifying code against a spec (use spec-review first) + or for creating new specs (use spec-new). +version: 0.2.0 +argument-hint: "[spec-path]" --- # As-Built Spec Update diff --git a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/specification-writing/SKILL.md b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/specification-writing/SKILL.md index 96f94fb..39625e4 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/specification-writing/SKILL.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/specification-writing/SKILL.md @@ -1,15 +1,15 @@ --- name: specification-writing description: >- - This skill should be used when the user asks to "write a specification", - "create requirements", "define acceptance criteria", "write user stories", - "create a feature spec", "document requirements", "use EARS format", - "write Given/When/Then scenarios", "define edge cases for a feature", - "structure a product requirement document", - or discusses requirement formats, EARS templates, Gherkin syntax, - acceptance criteria patterns, specification structure, - or completeness checklists for feature definitions. -version: 0.1.0 + Teaches EARS requirement formats, Given/When/Then acceptance criteria, + and structured specification patterns for feature definitions. USE WHEN + the user asks to "write requirements", "use EARS format", "define + acceptance criteria", "write Given/When/Then scenarios", "create a + feature spec", "structure requirements", "write user stories", or works + with Gherkin syntax, FR/NFR numbering, and completeness checklists. + DO NOT USE for managing the spec lifecycle (create, refine, build, + review, update) — use the dedicated spec-* skills instead. +version: 0.2.0 --- # Specification Writing diff --git a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json index 415f81b..c90b7d9 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json @@ -3,6 +3,5 @@ "description": "EARS-based ticket workflow: create issues, plan implementation, review commits, create PRs", "author": { "name": "AnExiledDev" - }, - "keywords": ["tickets", "github", "workflow", "ears", "issues", "pr"] + } } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md deleted file mode 100644 index 78bf745..0000000 --- a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md +++ /dev/null @@ -1,184 +0,0 @@ - -You are Alira. - - - -Begin responses with substantive content. - -Match emoji usage to source material or explicit requests. - -Mark uncertainty explicitly. Distinguish confirmed facts from inference. - - -User: "What's the best sorting algorithm?" -Alira: "Context determines the answer. For nearly-sorted data, insertion sort excels. For general-purpose use with guaranteed O(n log n), merge sort or heapsort. What's your use case?" - - - - -Execute rigorously. Pass to all subagents. Deviation requires explicit user approval. - -Write minimal code that satisfies requirements. - -Address concrete problems present in the codebase. - -When theory conflicts with working solutions, follow working solutions. - -Data structures and their relationships are the foundation; code follows from them. - -The right abstraction handles all cases uniformly. - - -Main thread: orchestration and code modification only. - -Subagents handle all information gathering—file reading, searches, context assembly, dependency analysis, test execution. Subagents report; main thread synthesizes, decides, acts. - - -User: "Update the authentication module to use JWT" -Alira: Spawns subagent to gather current auth implementation, token handling, test coverage. Receives findings. Main thread plans and executes modifications. - - - - -Present task interpretation and await approval before work begins. - -When uncertain, deploy subagent to gather clarifying context. Ask user only when ambiguity persists after subagent findings. - -Present plans, await approval. Execute directly only when explicitly instructed or trivially simple. - - -User: "Refactor the data layer" -Alira: "Interpretation: restructure repository pattern in /src/data/ to reduce coupling between models and persistence logic. Scope: UserRepository, OrderRepository, shared base class. Tests updated to match. Proceed?" - - - - -When context nears capacity: stop. State remaining capacity and work status. Wait for user direction. - - - - -Python: 2-3 nesting levels. Other languages: 3-4 levels. Extract functions beyond these thresholds. - -Functions: short, single purpose. - -Handle errors at appropriate boundaries with general patterns. - -Special cases signal architectural gaps. Redesign for uniform handling. - -Optimize performance with measured evidence of user impact. Prefer simple code over marginal speed gains. - -Verify changes preserve existing functionality. Document issues exceeding context limits and request guidance. - - -Inline comments explain *why*, only when non-obvious. Routine documentation belongs in docblocks: purpose, parameters, return values, usage. - - -# why (correct) -offset = len(header) + 1 # null terminator in legacy format - -# what (unnecessary) - -offset = len(header) + 1 # add one to header length - - - - -Files: small, focused, single purpose. One reason to change per file. - - -Single Responsibility: each module, class, function owns one concern. - -Open/Closed: extend behavior through composition and abstraction; existing code remains stable. - -Liskov Substitution: subtypes fulfill the contracts of their parents completely. - -Interface Segregation: small, specific interfaces. Clients depend only on methods they use. - -Dependency Inversion: depend on abstractions. High-level modules and low-level modules both point toward interfaces. - - - -DRY: single source of truth for knowledge and logic. Extract, reference, reuse. - -KISS: favor straightforward solutions. Complexity requires justification. - -YAGNI: implement for current requirements. Speculative features wait until needed. - -Convention over Configuration: follow established patterns; configure only where deviation is necessary. - -Law of Demeter: objects interact with immediate collaborators. Avoid reaching through chains. - - - -User: "Add email notifications when orders ship" -Alira: Creates NotificationService interface, EmailNotifier implementation, injects into OrderService. OrderService calls notifier.send()—unaware of email specifics. One file per component. - - - - - -GitHub issues are the single source of truth. All major decisions, plans, and progress MUST be posted as issue comments. - -Commands: /ticket:new, /ticket:work, /ticket:review-commit, /ticket:create-pr - -EARS requirements format (every requirement must use one): -- Ubiquitous: The shall . -- Event-Driven: WHEN , the shall . -- State-Driven: WHILE , the shall . -- Unwanted Behavior: IF , THEN the shall . -- Optional Feature: WHERE , the shall . - -Ticket structure: Overview (plain language) + Requirements (EARS) + Technical Questions + Acceptance Criteria - -Audit trail requirements: -- Plans → issue comment -- Decisions → issue comment -- Requirement changes → issue comment -- Commit summaries → issue comment -- Review findings → PR + issue comment -- Created issues → linked to source ticket - -Transparency rules: -- NEVER defer without express user approval -- NEVER mark out-of-scope without express user approval -- Present ALL findings, let user decide handling -- User chooses: fix now, create issue, or ignore - -Batching: Combine related GitHub comments/issues to avoid spam. Group review issues by category. - -Track current ticket in context. Support multiple tickets per session. - - - -Tests verify behavior, not implementation. Follow these rules strictly. - -Test scope: -- Test public interfaces and behavior, not internal implementation -- One test per logical behavior, not per line of code -- Focus on: happy path, error handling, boundary conditions -- Skip: trivial getters/setters, simple pass-through functions, framework code - -AI testing pitfalls to AVOID: -- Endless edge cases: 3-5 edge cases max per function, prioritize by risk -- Testing implementation: Don't test private methods, internal state, or call order -- Over-mocking: If you mock everything, you test nothing -- Brittle tests: Don't assert on exact error messages, log output, or timestamps -- Coverage theater: 100% coverage ≠ good tests; untested behavior with 60% > tested nothing with 100% - -Test file guidelines: -- Mirror source structure: src/foo.ts → tests/foo.test.ts -- One test file per source file (unless genuinely complex) -- Descriptive test names: "should reject expired tokens" not "test1" - -When tests are NOT required: -- User explicitly says "no tests" or "skip tests" -- Pure configuration changes (env vars, build config) -- Documentation-only changes -- Prototype/spike work marked as such - -When suggesting tests: -- Propose specific test scenarios, not vague "add tests for X" -- Estimate count: "2-3 unit tests for validation, 1 integration test for API" -- Ask user preference if scope is unclear - diff --git a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/README.md b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/README.md index 1cea73d..aeb47be 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/README.md @@ -74,6 +74,34 @@ Each ticket created by `/ticket:new` includes: The plugin injects a system prompt that defines the assistant persona, coding standards (SOLID, DRY, KISS, YAGNI), testing standards, and the ticket workflow rules. This ensures consistent behavior across all four commands. +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: + + ```json + { + "enabledPlugins": { + "ticket-workflow@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` + + Replace `` with the absolute path to your CodeForge clone. + ## Plugin Structure ``` diff --git a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/hooks/hooks.json index bfc6edf..0cda729 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/hooks/hooks.json @@ -3,7 +3,6 @@ "hooks": { "UserPromptSubmit": [ { - "matcher": "*", "hooks": [ { "type": "command", diff --git a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/scripts/ticket-linker.py b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/scripts/ticket-linker.py index bb11478..24a73ce 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/scripts/ticket-linker.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/scripts/ticket-linker.py @@ -129,7 +129,15 @@ def main(): if len(output) > TOTAL_OUTPUT_CAP: output = output[:TOTAL_OUTPUT_CAP] + "\n...(truncated)" - json.dump({"additionalContext": output}, sys.stdout) + json.dump( + { + "hookSpecificOutput": { + "hookEventName": "UserPromptSubmit", + "additionalContext": output, + } + }, + sys.stdout, + ) sys.exit(0) diff --git "a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272create-pr.md" b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketcreate-pr/SKILL.md similarity index 100% rename from ".devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272create-pr.md" rename to .devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketcreate-pr/SKILL.md diff --git "a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272new.md" b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketnew/SKILL.md similarity index 100% rename from ".devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272new.md" rename to .devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketnew/SKILL.md diff --git "a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272review-commit.md" b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketreview-commit/SKILL.md similarity index 100% rename from ".devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272review-commit.md" rename to .devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketreview-commit/SKILL.md diff --git "a/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272work.md" b/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketwork/SKILL.md similarity index 100% rename from ".devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket\357\200\272work.md" rename to .devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/skills/ticketwork/SKILL.md diff --git a/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md index 1a3cd99..9013b1f 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md @@ -1,33 +1,49 @@ # workspace-scope-guard -Claude Code plugin that enforces working directory scope for all file operations. Blocks writes outside the current project directory and warns on reads outside it. Prevents accidental cross-project modifications in multi-project workspaces. +Nuclear workspace scope enforcement for Claude Code. Blocks ALL operations (read, write, bash) outside the current working directory. Permanently blacklists `/workspaces/.devcontainer/` — no exceptions, no bypass, even from workspace root. ## What It Does -Intercepts file operations (Read, Write, Edit, NotebookEdit, Glob, Grep) and checks whether the target path is within the current working directory: +Intercepts all file and bash operations and enforces strict scope boundaries: | Operation | Out-of-scope behavior | |-----------|-----------------------| -| Write, Edit, NotebookEdit | **Blocked** (exit 2) with error message | -| Read, Glob, Grep | **Warned** (exit 0) with advisory context | +| Write, Edit, NotebookEdit | **Blocked** (exit 2) | +| Read, Glob, Grep | **Blocked** (exit 2) | +| Bash | **Blocked** (exit 2) — two-layer detection | +| Unknown tools | **Blocked** (exit 2) | -When the current working directory is `/workspaces` (the workspace root), all operations are unrestricted. +### Blacklisted Paths -### Allowed Prefixes +`/workspaces/.devcontainer/` is permanently blocked for ALL operations — reads, writes, and bash commands. This blacklist: + +- Runs BEFORE all other checks (scope, allowlist, cwd bypass) +- Cannot be overridden, even when cwd is `/workspaces` +- Prevents the most common scope escape: writing to the workspace-root devcontainer instead of the project's + +### Allowlisted Paths These paths are always permitted regardless of working directory: | Path | Reason | |------|--------| -| `/workspaces/.claude/` | Claude Code configuration | -| `/workspaces/.tmp/` | Temporary files | -| `/workspaces/.devcontainer/` | Container configuration | +| `/workspaces/.claude/` | Claude config, plans, rules | | `/tmp/` | System temp directory | -| `/home/vscode/` | User home directory | + +### CWD Context Injection + +The plugin injects working directory awareness on four hook events: + +| Hook Event | Purpose | +|-----------|---------| +| SessionStart | Set scope context at session begin | +| UserPromptSubmit | Remind scope on every prompt | +| PreToolUse | Context alongside scope enforcement | +| SubagentStart | Ensure subagents know their scope | ## How It Works -### Hook Lifecycle +### Hook Lifecycle (File Tools) ``` Claude calls Read, Write, Edit, NotebookEdit, Glob, or Grep @@ -36,24 +52,43 @@ Claude calls Read, Write, Edit, NotebookEdit, Glob, or Grep │ └─→ guard-workspace-scope.py │ - ├─→ cwd is /workspaces? → allow (unrestricted) - ├─→ No target path? → allow (tool defaults to cwd) - ├─→ Resolve path via os.path.realpath() (handles symlinks/worktrees) - ├─→ Path is within cwd? → allow - ├─→ Path matches allowed prefix? → allow - ├─→ Write tool + out of scope → exit 2 (block) - └─→ Read tool + out of scope → exit 0 (warn via additionalContext) + ├─→ Extract target path from tool input + ├─→ Resolve via os.path.realpath() (handles symlinks) + ├─→ BLACKLIST check (first!) → exit 2 if blacklisted + ├─→ cwd is /workspaces? → allow (bypass, blacklist already checked) + ├─→ Path within cwd? → allow + ├─→ Path on allowlist? → allow + └─→ Out of scope → exit 2 (block) ``` -### Symlink and Worktree Handling +### Hook Lifecycle (Bash) + +``` +Claude calls Bash + │ + └─→ PreToolUse hook fires + │ + └─→ guard-workspace-scope.py + │ + ├─→ Extract write targets (Layer 1) + workspace paths (Layer 2) + ├─→ BLACKLIST check on ALL extracted paths → exit 2 if any blacklisted + ├─→ cwd is /workspaces? → allow (bypass, blacklist already checked) + ├─→ Layer 1: Check write targets against scope + │ ├─→ System command exemption (only if ALL targets are system paths) + │ └─→ exit 2 if any write target out of scope + └─→ Layer 2: Scan ALL /workspaces/ paths in command (ALWAYS runs) + └─→ exit 2 if any workspace path out of scope +``` -Target paths are resolved with `os.path.realpath()` before scope checking. This correctly handles: -- Symbolic links that point outside the working directory -- Git worktree paths (`.git` file containing `gitdir:`) +### Bash Two-Layer Detection -### Path Field Mapping +**Layer 1 — Write target extraction:** 20+ regex patterns extract file paths from write operations (redirects, cp, mv, touch, mkdir, rm, ln, rsync, chmod, chown, dd, wget, curl, tar, unzip, gcc, sqlite3, etc.). Each target is resolved and scope-checked. -The script extracts the target path from different tool input fields: +System commands (git, pip, npm, etc.) get a Layer 1 exemption ONLY when ALL write targets resolve to system paths (`/usr/`, `/bin/`, `/sbin/`, `/lib/`, `/opt/`, `/proc/`, `/sys/`, `/dev/`, `/var/`, `/etc/`). Any `/workspaces/` write target outside cwd cancels the exemption. + +**Layer 2 — Workspace path scan (ALWAYS runs):** Regex scans the entire command for any `/workspaces/` path string. Catches paths in inline scripts (`python3 -c`), variable assignments, quoted strings, and anything Layer 1 misses. No exemptions, no bypass. + +### Path Field Mapping | Tool | Input Field | |------|-------------| @@ -63,29 +98,66 @@ The script extracts the target path from different tool input fields: | NotebookEdit | `notebook_path` | | Glob | `path` | | Grep | `path` | +| Bash | `command` (multi-path extraction) | ### Error Handling | Scenario | Behavior | |----------|----------| -| JSON parse failure | Fails open (exit 0) | -| Other exceptions | Fails open (exit 0) — logs error to stderr | +| JSON parse failure | **Blocked** (exit 2) — fail closed | +| Any exception | **Blocked** (exit 2) — fail closed | +| Hook timeout | Fails open (Claude Code runtime limitation) — mitigated by 10s timeout and pure computation (no I/O) | + +## Known Limitations + +| Limitation | Why It's Accepted | +|-----------|-------------------| +| Pre-set env vars (`$OUTDIR/file` from prior command) | Layer 2 only catches literal `/workspaces/` strings. Variable set in same command IS caught. | +| Base64-encoded paths | Not an accidental misuse pattern | +| Bash brace expansion | Not an accidental directory construction pattern | +| Variable concatenation across statements | No single literal path exists to match | +| Hook timeout fails open | Mitigated: 10s timeout, pure computation, no I/O | + +## Installation + +### CodeForge DevContainer + +Pre-installed and activated automatically — no setup needed. + +### From GitHub + +Use this plugin in any Claude Code setup: + +1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository: + + ```bash + git clone https://github.com/AnExiledDev/CodeForge.git + ``` + +2. Enable the plugin in your `.claude/settings.json`: -### Timeout + ```json + { + "enabledPlugins": { + "workspace-scope-guard@/.devcontainer/plugins/devs-marketplace": true + } + } + ``` -The hook has a 5-second timeout. + Replace `` with the absolute path to your CodeForge clone. ## Plugin Structure ``` workspace-scope-guard/ ├── .claude-plugin/ -│ └── plugin.json # Plugin metadata +│ └── plugin.json # Plugin metadata ├── hooks/ -│ └── hooks.json # PreToolUse hook registration +│ └── hooks.json # Hook registrations (6 events) ├── scripts/ -│ └── guard-workspace-scope.py # Scope enforcement (PreToolUse) -└── README.md # This file +│ ├── guard-workspace-scope.py # Scope enforcement (PreToolUse) +│ └── inject-workspace-cwd.py # CWD context injection (4 events) +└── README.md # This file ``` ## Requirements diff --git a/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/hooks/hooks.json b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/hooks/hooks.json index f6e1dbb..1c3e557 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/hooks/hooks.json +++ b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/hooks/hooks.json @@ -1,14 +1,60 @@ { - "description": "Enforce workspace scope for file operations", + "description": "Nuclear workspace scope enforcement — blocks all operations outside cwd, permanently blacklists /workspaces/.devcontainer/", "hooks": { "PreToolUse": [ { - "matcher": "Read|Write|Edit|NotebookEdit|Glob|Grep", + "matcher": "Read|Write|Edit|NotebookEdit|Glob|Grep|Bash", "hooks": [ { "type": "command", "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/guard-workspace-scope.py", - "timeout": 5 + "timeout": 10 + } + ] + }, + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/inject-workspace-cwd.py", + "timeout": 3 + } + ] + } + ], + "SessionStart": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/inject-workspace-cwd.py", + "timeout": 3 + } + ] + } + ], + "UserPromptSubmit": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/inject-workspace-cwd.py", + "timeout": 3 + } + ] + } + ], + "SubagentStart": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/inject-workspace-cwd.py", + "timeout": 3 } ] } diff --git a/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py index 5273882..2c95080 100755 --- a/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py @@ -1,29 +1,41 @@ #!/usr/bin/env python3 """ -Enforce workspace scope for file operations. +Nuclear workspace scope enforcement. -Blocks write operations (Write, Edit, NotebookEdit) to files outside the -current working directory. Warns on read operations (Read, Glob, Grep) -outside the working directory. Allows unrestricted access when cwd is -/workspaces (the workspace root). +Blocks ALL operations (read, write, bash) outside the current working directory. +Permanently blacklists /workspaces/.devcontainer/ — no exceptions, no bypass. +Bash enforcement via two-layer detection: write target extraction + workspace path scan. +Fails closed on any error. Exit code 2 blocks the operation with an error message. -Exit code 0 allows the operation to proceed (with optional warning context). +Exit code 0 allows the operation to proceed. """ import json import os +import re +import shlex import sys -# Paths that are always allowed regardless of working directory +# --------------------------------------------------------------------------- +# BLACKLIST — checked FIRST, overrides everything. +# Nothing touches these paths. Ever. No exceptions. +# Checked before allowlist, before scope check, before cwd bypass. +# --------------------------------------------------------------------------- +BLACKLISTED_PREFIXES = [ + "/workspaces/.devcontainer/", + "/workspaces/.devcontainer", # exact match (no trailing slash) +] + +# Paths always allowed regardless of working directory ALLOWED_PREFIXES = [ - "/workspaces/.tmp/", - "/tmp/", - "/home/vscode/", + "/workspaces/.claude/", # Claude config, plans, rules + "/tmp/", # System scratch ] WRITE_TOOLS = {"Write", "Edit", "NotebookEdit"} READ_TOOLS = {"Read", "Glob", "Grep"} +ALL_FILE_TOOLS = WRITE_TOOLS | READ_TOOLS # Tool input field that contains the target path PATH_FIELDS = { @@ -35,6 +47,76 @@ "Grep": "path", } +# --------------------------------------------------------------------------- +# Bash Layer 1: Write target patterns +# Ported from guard-protected-bash.py + new patterns +# --------------------------------------------------------------------------- +WRITE_PATTERNS = [ + # --- Ported from guard-protected-bash.py --- + r"(?:>|>>)\s*([^\s;&|]+)", # > file, >> file + r"\btee\s+(?:-a\s+)?([^\s;&|]+)", # tee file + r"\b(?:cp|mv)\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # cp/mv src dest + r'\bsed\s+-i[^\s]*\s+(?:\'[^\']*\'\s+|"[^"]*"\s+|[^\s]+\s+)*([^\s;&|]+)', # sed -i + r"\bcat\s+(?:<<[^\s]*\s+)?>\s*([^\s;&|]+)", # cat > file + # --- New patterns --- + r"\btouch\s+(?:-[^\s]+\s+)*([^\s;&|]+)", # touch file + r"\bmkdir\s+(?:-[^\s]+\s+)*([^\s;&|]+)", # mkdir [-p] dir + r"\brm\s+(?:-[^\s]+\s+)*([^\s;&|]+)", # rm [-rf] path + r"\bln\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # ln [-s] src dest + r"\binstall\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # install src dest + r"\brsync\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # rsync src dest + r"\bchmod\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # chmod mode path + r"\bchown\s+(?:-[^\s]+\s+)*[^\s:]+(?::[^\s]+)?\s+([^\s;&|]+)", # chown owner[:group] path + r"\bdd\b[^;|&]*\bof=([^\s;&|]+)", # dd of=path + r"\bwget\s+(?:-[^\s]+\s+)*-O\s+([^\s;&|]+)", # wget -O path + r"\bcurl\s+(?:-[^\s]+\s+)*-o\s+([^\s;&|]+)", # curl -o path + r"\btar\s+(?:-[^\s]+\s+)*-C\s+([^\s;&|]+)", # tar -C dir + r"\bunzip\s+(?:-[^\s]+\s+)*-d\s+([^\s;&|]+)", # unzip -d dir + r"\b(?:gcc|g\+\+|cc|c\+\+|clang)\s+(?:-[^\s]+\s+)*-o\s+([^\s;&|]+)", # gcc -o out + r"\bsqlite3\s+([^\s;&|]+)", # sqlite3 dbpath +] + +# --------------------------------------------------------------------------- +# Bash Layer 2: Workspace path scan (ALWAYS runs, never exempt) +# Stops at: whitespace, ;, |, &, >, ), <, ', " +# --------------------------------------------------------------------------- +WORKSPACE_PATH_RE = re.compile(r'/workspaces/[^\s;|&>)<\'"]+') + +# --------------------------------------------------------------------------- +# System command exemption (Layer 1 only) +# --------------------------------------------------------------------------- +SYSTEM_COMMANDS = frozenset({ + "git", "pip", "pip3", "npm", "npx", "yarn", "pnpm", + "apt-get", "apt", "cargo", "go", "docker", "make", "cmake", + "node", "python3", "python", "ruby", "gem", "bundle", +}) + +SYSTEM_PATH_PREFIXES = ( + "/usr/", "/bin/", "/sbin/", "/lib/", "/opt/", + "/proc/", "/sys/", "/dev/", "/var/", "/etc/", +) + + +# --------------------------------------------------------------------------- +# Core check functions +# --------------------------------------------------------------------------- + +def is_blacklisted(resolved_path: str) -> bool: + """Check if resolved_path is under a permanently blocked directory.""" + return (resolved_path == "/workspaces/.devcontainer" + or resolved_path.startswith("/workspaces/.devcontainer/")) + + +def is_in_scope(resolved_path: str, cwd: str) -> bool: + """Check if resolved_path is within the working directory.""" + cwd_prefix = cwd if cwd.endswith("/") else cwd + "/" + return resolved_path == cwd or resolved_path.startswith(cwd_prefix) + + +def is_allowlisted(resolved_path: str) -> bool: + """Check if resolved_path falls under an allowed prefix.""" + return any(resolved_path.startswith(prefix) for prefix in ALLOWED_PREFIXES) + def get_target_path(tool_name: str, tool_input: dict) -> str | None: """Extract the target path from tool input. @@ -48,16 +130,147 @@ def get_target_path(tool_name: str, tool_input: dict) -> str | None: return tool_input.get(field) or None -def is_in_scope(resolved_path: str, cwd: str) -> bool: - """Check if resolved_path is within the working directory.""" - cwd_prefix = cwd if cwd.endswith("/") else cwd + "/" - return resolved_path == cwd or resolved_path.startswith(cwd_prefix) +# --------------------------------------------------------------------------- +# Bash enforcement +# --------------------------------------------------------------------------- +def extract_write_targets(command: str) -> list[str]: + """Extract file paths that the command writes to (Layer 1).""" + targets = [] + for pattern in WRITE_PATTERNS: + for match in re.finditer(pattern, command): + target = match.group(1).strip("'\"") + if target: + targets.append(target) + return targets -def is_allowlisted(resolved_path: str) -> bool: - """Check if resolved_path falls under an allowed prefix.""" - return any(resolved_path.startswith(prefix) for prefix in ALLOWED_PREFIXES) +def extract_primary_command(command: str) -> str: + """Extract the primary command, stripping sudo/env/variable prefixes.""" + try: + tokens = shlex.split(command) + except ValueError: + # Unclosed quotes or other parse errors — no exemption + return "" + i = 0 + while i < len(tokens): + tok = tokens[i] + # Skip inline variable assignments: VAR=value + if "=" in tok and not tok.startswith("-") and tok.split("=")[0].isidentifier(): + i += 1 + continue + # Skip sudo and its flags + if tok == "sudo": + i += 1 + while i < len(tokens) and tokens[i].startswith("-"): + flag = tokens[i] + i += 1 + # Flags that consume the next token as an argument + if flag in ("-u", "-g", "-C", "-D", "-R", "-T"): + i += 1 # skip the argument too + continue + # Skip env and its variable assignments + if tok == "env": + i += 1 + while i < len(tokens): + if "=" in tokens[i] and not tokens[i].startswith("-"): + i += 1 # skip VAR=val + elif tokens[i].startswith("-"): + i += 1 # skip env flags (-i, etc.) + else: + break + continue + # Skip nohup, nice, time + if tok in ("nohup", "nice", "time"): + i += 1 + continue + return tok + return "" + + +def check_bash_scope(command: str, cwd: str) -> None: + """Enforce scope on Bash commands. Calls sys.exit(2) on violation.""" + if not command: + return + + # --- Extract paths from command --- + write_targets = extract_write_targets(command) + workspace_paths = WORKSPACE_PATH_RE.findall(command) + + # --- BLACKLIST check (FIRST — before cwd bypass, before everything) --- + # Early exit on first blacklisted path found + for target in write_targets: + resolved = os.path.realpath(target.strip("'\"")) + if is_blacklisted(resolved): + print( + f"Blocked: Bash command writes to blacklisted path '{target}'. " + f"/workspaces/.devcontainer/ is permanently blocked.", + file=sys.stderr, + ) + sys.exit(2) + + for path_str in workspace_paths: + resolved = os.path.realpath(path_str) + if is_blacklisted(resolved): + print( + f"Blocked: Bash command references blacklisted path '{path_str}'. " + f"/workspaces/.devcontainer/ is permanently blocked.", + file=sys.stderr, + ) + sys.exit(2) + + # --- cwd=/workspaces bypass (blacklist already checked above) --- + if cwd == "/workspaces": + return + + # --- Layer 1: Write target scope check --- + if write_targets: + primary_cmd = extract_primary_command(command) + is_system_cmd = primary_cmd in SYSTEM_COMMANDS + + resolved_targets = [ + (t, os.path.realpath(t.strip("'\""))) for t in write_targets + ] + + # System command exemption: skip Layer 1 ONLY if ALL targets are system paths + skip_layer1 = False + if is_system_cmd: + skip_layer1 = all( + any(r.startswith(sp) for sp in SYSTEM_PATH_PREFIXES) + for _, r in resolved_targets + ) + # Override: if ANY target is under /workspaces/ outside cwd → NOT exempt + if skip_layer1: + for _, resolved in resolved_targets: + if resolved.startswith("/workspaces/") and not is_in_scope(resolved, cwd): + skip_layer1 = False + break + + if not skip_layer1: + for target, resolved in resolved_targets: + if not is_in_scope(resolved, cwd) and not is_allowlisted(resolved): + print( + f"Blocked: Bash command writes to '{target}' which is " + f"outside the working directory ({cwd}).", + file=sys.stderr, + ) + sys.exit(2) + + # --- Layer 2: Workspace path scan (ALWAYS runs, never exempt) --- + for path_str in workspace_paths: + resolved = os.path.realpath(path_str) + if not is_in_scope(resolved, cwd) and not is_allowlisted(resolved): + print( + f"Blocked: Bash command references '{path_str}' which is " + f"outside the working directory ({cwd}).", + file=sys.stderr, + ) + sys.exit(2) + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- def main(): try: @@ -67,63 +280,63 @@ def main(): cwd = os.getcwd() - # Unrestricted when working from the workspace root - if cwd == "/workspaces": + # --- Bash tool: separate code path --- + if tool_name == "Bash": + check_bash_scope(tool_input.get("command", ""), cwd) sys.exit(0) + # --- File tools --- target_path = get_target_path(tool_name, tool_input) - # No path specified — tool defaults to cwd, which is in scope + # No path → tool defaults to cwd, always in scope (for known file tools) if target_path is None: - sys.exit(0) + if tool_name in ALL_FILE_TOOLS: + sys.exit(0) + # Unknown tool with no recognizable path → block + print( + f"Blocked: Unknown tool '{tool_name}' — not in scope guard allowlist.", + file=sys.stderr, + ) + sys.exit(2) resolved = os.path.realpath(target_path) - if is_in_scope(resolved, cwd): - sys.exit(0) - - if is_allowlisted(resolved): - sys.exit(0) - - # Out of scope - if tool_name in WRITE_TOOLS: + # BLACKLIST — checked FIRST, before cwd bypass + if is_blacklisted(resolved): print( - json.dumps( - { - "error": ( - f"Blocked: {tool_name} targets '{target_path}' which is " - f"outside the working directory ({cwd}). Move to that " - f"project's directory first or work from /workspaces." - ) - } - ) + f"Blocked: {tool_name} targets '{target_path}' which is under " + f"blacklisted path /workspaces/.devcontainer/. This path is " + f"permanently blocked for all operations.", + file=sys.stderr, ) sys.exit(2) - if tool_name in READ_TOOLS: - print( - json.dumps( - { - "additionalContext": ( - f"Warning: {tool_name} targets '{target_path}' which is " - f"outside the working directory ({cwd}). This read is " - f"allowed but may indicate unintended cross-project access." - ) - } - ) - ) + # cwd=/workspaces bypass (blacklist already checked) + if cwd == "/workspaces": + sys.exit(0) + + # In-scope check + if is_in_scope(resolved, cwd): + sys.exit(0) + + # Allowlist check + if is_allowlisted(resolved): sys.exit(0) - # Unknown tool — allow by default - sys.exit(0) + # Out of scope — BLOCK for ALL tools + print( + f"Blocked: {tool_name} targets '{target_path}' which is outside " + f"the working directory ({cwd}). Move to that project's directory " + f"first or work from /workspaces.", + file=sys.stderr, + ) + sys.exit(2) except json.JSONDecodeError: - # Can't parse input — allow by default - sys.exit(0) + sys.exit(2) except Exception as e: - # Don't block on hook failure print(f"Hook error: {e}", file=sys.stderr) - sys.exit(0) + sys.exit(2) if __name__ == "__main__": diff --git a/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/inject-workspace-cwd.py b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/inject-workspace-cwd.py new file mode 100644 index 0000000..64a3efb --- /dev/null +++ b/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/inject-workspace-cwd.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +""" +CWD context injector — injects working directory into Claude's context +on every session start, user prompt, tool call, and subagent spawn. + +Fires on: SessionStart, UserPromptSubmit, PreToolUse, SubagentStart +Always exits 0 (advisory, never blocking). +""" + +import json +import os +import sys + + +def main(): + cwd = os.getcwd() + try: + input_data = json.load(sys.stdin) + # Some hook events provide cwd override + cwd = input_data.get("cwd", cwd) + hook_event = input_data.get("hook_event_name", "PreToolUse") + except (json.JSONDecodeError, ValueError): + hook_event = "PreToolUse" + + context = ( + f"Working Directory: {cwd}\n" + f"All file operations and commands MUST target paths within {cwd}. " + f"Do not read, write, or execute commands against paths outside this directory." + ) + + json.dump( + { + "hookSpecificOutput": { + "hookEventName": hook_event, + "additionalContext": context, + } + }, + sys.stdout, + ) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/.devcontainer/scripts/setup-aliases.sh b/.devcontainer/scripts/setup-aliases.sh index 7b47d95..3e15818 100755 --- a/.devcontainer/scripts/setup-aliases.sh +++ b/.devcontainer/scripts/setup-aliases.sh @@ -70,6 +70,7 @@ for rc in ~/.bashrc ~/.zshrc; do ${BLOCK_START} export CLAUDE_CONFIG_DIR="${CLAUDE_CONFIG_DIR}" +export GH_CONFIG_DIR="${GH_CONFIG_DIR:-/workspaces/.gh}" export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 @@ -82,10 +83,17 @@ else _CLAUDE_BIN=claude fi -alias cc='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/main-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions' -alias claude='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/main-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions' +# ChromaTerm wrapper (if ct is installed, wrap claude through it) +if command -v ct >/dev/null 2>&1; then + _CLAUDE_WRAP="ct" +else + _CLAUDE_WRAP="command" +fi + +alias cc='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 "\$_CLAUDE_WRAP" "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/main-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions' +alias claude='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 "\$_CLAUDE_WRAP" "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/main-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions' alias ccraw='command "\$_CLAUDE_BIN"' -alias ccw='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/writing-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions' +alias ccw='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 "\$_CLAUDE_WRAP" "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/writing-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions' cc-tools() { echo "CodeForge Available Tools" @@ -93,9 +101,9 @@ cc-tools() { printf " %-20s %s\n" "COMMAND" "STATUS" echo " ────────────────────────────────────" for cmd in claude cc ccw ccraw ccusage ccburn claude-monitor \\ - ccms cargo ruff biome dprint shfmt shellcheck hadolint \\ + ccms ct cargo ruff biome dprint shfmt shellcheck hadolint \\ ast-grep tree-sitter pyright typescript-language-server \\ - agent-browser gh docker git jq tmux bun go; do + agent-browser gh docker git jq tmux bun go infocmp; do if command -v "\$cmd" >/dev/null 2>&1; then ver=\$("\$cmd" --version 2>/dev/null | head -1 || echo "installed") printf " %-20s ✓ %s\n" "\$cmd" "\$ver" diff --git a/.devcontainer/scripts/setup-config.sh b/.devcontainer/scripts/setup-config.sh index d2cd36e..6b923a6 100755 --- a/.devcontainer/scripts/setup-config.sh +++ b/.devcontainer/scripts/setup-config.sh @@ -45,6 +45,7 @@ expand_vars() { local val="$1" val="${val//\$\{CLAUDE_CONFIG_DIR\}/$CLAUDE_CONFIG_DIR}" val="${val//\$\{WORKSPACE_ROOT\}/$WORKSPACE_ROOT}" + val="${val//\$\{HOME\}/$HOME}" # Warn on any remaining unresolved ${...} tokens if [[ "$val" =~ \$\{[^}]+\} ]]; then warn "Unresolved variable in: $val" diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..e445896 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,44 @@ +name: Deploy Docs + +on: + push: + branches: [main] + paths: ['docs/**', '.devcontainer/CHANGELOG.md'] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + cache-dependency-path: docs/package-lock.json + - run: npm ci + working-directory: docs + - run: npm run build + working-directory: docs + - uses: actions/upload-pages-artifact@v3 + with: + path: docs/dist + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/docs-ci.yml b/.github/workflows/docs-ci.yml new file mode 100644 index 0000000..05a66b1 --- /dev/null +++ b/.github/workflows/docs-ci.yml @@ -0,0 +1,20 @@ +name: Docs CI + +on: + pull_request: + paths: ['docs/**', '.devcontainer/CHANGELOG.md'] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + cache-dependency-path: docs/package-lock.json + - run: npm ci + working-directory: docs + - run: npm run build + working-directory: docs diff --git a/.github/workflows/publish-features.yml b/.github/workflows/publish-features.yml new file mode 100644 index 0000000..20bdca7 --- /dev/null +++ b/.github/workflows/publish-features.yml @@ -0,0 +1,25 @@ +name: "Publish DevContainer Features" + +on: + workflow_dispatch: + push: + branches: [main] + paths: ['.devcontainer/features/**'] + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - uses: actions/checkout@v4 + + - name: "Publish Features" + uses: devcontainers/action@v1 + with: + publish-features: "true" + base-path-to-features: "./.devcontainer/features" + generate-docs: "false" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e9eb85f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,75 @@ +name: Release + +on: + push: + branches: [main] + paths: ['package.json'] + +jobs: + check-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.check.outputs.version }} + changed: ${{ steps.check.outputs.changed }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - id: check + run: | + CURRENT=$(node -p "require('./package.json').version") + PREVIOUS=$(git show HEAD~1:package.json | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version" || echo "0.0.0") + echo "version=$CURRENT" >> "$GITHUB_OUTPUT" + if [ "$CURRENT" != "$PREVIOUS" ]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + else + echo "changed=false" >> "$GITHUB_OUTPUT" + fi + + publish-and-release: + needs: check-version + if: needs.check-version.outputs.changed == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 18 + registry-url: https://registry.npmjs.org + + - name: Run tests + run: npm test + + - name: Publish to npm + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Create git tag + run: | + VERSION="v${{ needs.check-version.outputs.version }}" + git tag "$VERSION" + git push origin "$VERSION" + + - name: Extract changelog section + id: changelog + run: | + VERSION="${{ needs.check-version.outputs.version }}" + NOTES=$(sed -n "/^## \[v${VERSION}\]/,/^## \[v/{ /^## \[v${VERSION}\]/d; /^## \[v/d; p; }" .devcontainer/CHANGELOG.md) + if [ -z "$NOTES" ]; then + NOTES="Release v${VERSION}" + fi + echo "$NOTES" > /tmp/release-notes.md + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="v${{ needs.check-version.outputs.version }}" + gh release create "$VERSION" \ + --title "$VERSION" \ + --notes-file /tmp/release-notes.md diff --git a/.gitignore b/.gitignore index 24a66c3..47550ad 100644 --- a/.gitignore +++ b/.gitignore @@ -63,26 +63,6 @@ node_modules/ # Claude Code directory (user-specific) .claude/ -# Work in progress -review-cli/ - -# CodeDirective project (separate product) -/code-directive/ - -# Research & working files (not part of CodeForge) -article/ -claude-research/ -claude-dev-discord-logs/ -dashboard/ -devforge/ -simple-review/ -devs-utilities/ -devs-notes/ -equicord-autobump/ - -# Unfinished plugins -.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/ - # All hidden directories except devcontainer .* !.devcontainer/ @@ -90,8 +70,14 @@ equicord-autobump/ !.devcontainer/ !.devcontainer/**/.claude-plugin/**/.claude-plugin/ !.git/ +!.github/ !.gitignore !.gitattributes !.npmignore .devcontainer/config/claude/output-styles/strict-development.md .devcontainer/config/claude/mcp.json + +# Docs +docs/node_modules/ +docs/dist/ +docs/.astro/ diff --git a/.npmignore b/.npmignore index 5e24b6e..4a3f235 100644 --- a/.npmignore +++ b/.npmignore @@ -6,8 +6,6 @@ test.js .devcontainer/config/backups/ # Documentation that's not needed in package -analysis.md -searxng-implementation.md docs/ # Git and development @@ -46,6 +44,6 @@ Thumbs.db **/__pycache__/ *.pyc -# Local development -.claude-trace/ -aeris-memory/ \ No newline at end of file +# Secrets (never publish) +.secrets +.devcontainer/.secrets \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 68b00a9..a7d4a2a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,27 @@ -# Workspace +# CodeForge -This workspace contains multiple independent projects under `/workspaces/`. -Each project is its own codebase. Stay within the current project directory -unless explicitly asked to work across projects. +DevContainer configuration project for AI-assisted development with Claude Code. -Do not explore, modify, or reference sibling project directories. +See `.devcontainer/CLAUDE.md` for full devcontainer documentation. + +## Development Rules + +### Changelog + +Every change MUST have a corresponding entry in `.devcontainer/CHANGELOG.md`. + +- New features, enhancements, fixes, and removals each get their own bullet +- Group related changes under the appropriate `### Added`, `### Changed`, `### Fixed`, or `### Removed` heading +- Use sub-headings (`####`) to organize by area (e.g., Workspace Scope Guard, Features, Configuration) +- If an unreleased version section doesn't exist, add changes to the current version's section +- Write entries from the user's perspective — what changed, not how it was implemented + +### Documentation + +All user-facing changes MUST be reflected in documentation: + +- **Plugin changes** → update the plugin's `README.md` +- **Feature changes** → update `features/README.md` and the feature's `devcontainer-feature.json` if applicable +- **Config system changes** → update `.devcontainer/CLAUDE.md` +- **New config files in `config/defaults/`** → add entry to `config/file-manifest.json` +- **Docs site** → update relevant pages in `docs/` if the docs site exists diff --git a/README.md b/README.md index 0a0605e..7fcc455 100644 --- a/README.md +++ b/README.md @@ -66,13 +66,13 @@ tree-sitter (JS/TS/Python), ast-grep, Pyright, TypeScript LSP `claude`, `cc` (wrapper), `ccw` (writing mode wrapper), `ccusage`, `ccburn`, `ccstatusline`, `claude-monitor` -### Custom Features (18) +### Custom Features (21) -tmux, agent-browser, claude-monitor, ccusage, ccburn, ccstatusline, ast-grep, tree-sitter, lsp-servers, biome, ruff, shfmt, shellcheck, hadolint, dprint, ccms, notify-hook, mcp-qdrant +tmux, agent-browser, claude-monitor, ccusage, ccburn, ccstatusline, ast-grep, tree-sitter, lsp-servers, biome, ruff, shfmt, shellcheck, hadolint, dprint, ccms, notify-hook, mcp-qdrant, chromaterm, kitty-terminfo, claude-session-dashboard -### Agents (17) & Skills (28) +### Agents (17) & Skills (34) -The `code-directive` plugin includes 17 specialized agents (architect, explorer, test-writer, security-auditor, etc.) and 28 domain-specific coding reference skills (fastapi, svelte5, docker, testing, spec-workflow, security-checklist, etc.). +The `agent-system` plugin includes 17 specialized agents (architect, explorer, test-writer, security-auditor, etc.). The `skill-engine` plugin provides 21 general coding skills, `spec-workflow` adds 8 spec lifecycle skills, and `ticket-workflow` provides 4 ticket management skills. ## Quick Start @@ -102,7 +102,7 @@ npm publish ## Changelog -See [CHANGELOG.md](.devcontainer/CHANGELOG.md) for release history. Current version: **1.12.0** (2026-02-18). +See [CHANGELOG.md](.devcontainer/CHANGELOG.md) for release history. Current version: **1.14.0** (2026-02-23). ## Further Reading diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 0000000..970dbb0 --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,177 @@ +import { defineConfig } from 'astro/config'; +import starlight from '@astrojs/starlight'; +import tailwindcss from '@tailwindcss/vite'; +import sitemap from '@astrojs/sitemap'; +import astroMermaid from 'astro-mermaid'; +import starlightSidebarTopics from 'starlight-sidebar-topics'; +import starlightImageZoom from 'starlight-image-zoom'; +import starlightLinksValidator from 'starlight-links-validator'; +import starlightKbd from 'starlight-kbd'; +import starlightScrollToTop from 'starlight-scroll-to-top'; +import starlightLlmsTxt from 'starlight-llms-txt'; + +export default defineConfig({ + site: 'https://anexileddev.github.io', + base: '/CodeForge', + integrations: [ + // astro-mermaid MUST be registered BEFORE starlight + astroMermaid(), + starlight({ + title: 'CodeForge', + tagline: 'Your AI dev environment, battle-tested.', + logo: { + src: './src/assets/logo.png', + replacesTitle: false, + }, + social: [ + { icon: 'github', label: 'GitHub', href: 'https://github.com/AnExiledDev/CodeForge' }, + { icon: 'x.com', label: 'X', href: 'https://x.com/AnExiledDev' }, + ], + customCss: ['./src/styles/global.css'], + components: { + Hero: './src/components/Hero.astro', + Header: './src/components/Header.astro', + }, + editLink: { + baseUrl: 'https://github.com/AnExiledDev/CodeForge/edit/main/docs/', + }, + head: [ + { + tag: 'meta', + attrs: { + name: 'og:image', + content: '/CodeForge/og-image.png', + }, + }, + { + tag: 'link', + attrs: { + rel: 'icon', + type: 'image/png', + href: '/CodeForge/favicon.png', + }, + }, + { + tag: 'link', + attrs: { + rel: 'apple-touch-icon', + href: '/CodeForge/apple-touch-icon.png', + }, + }, + { + // Default to dark theme when no user preference is saved + tag: 'script', + attrs: { is: 'inline' }, + content: `(function(){var k='starlight-theme';if(!localStorage.getItem(k)){localStorage.setItem(k,'dark');document.documentElement.setAttribute('data-theme','dark');document.documentElement.style.colorScheme='dark'}})()`, + }, + ], + plugins: [ + starlightSidebarTopics( + [ + { + label: 'Getting Started', + link: '/getting-started/', + icon: 'rocket', + items: [ + { label: 'Overview', slug: 'getting-started' }, + { label: 'Requirements', slug: 'getting-started/requirements' }, + { label: 'Installation', slug: 'getting-started/installation' }, + { label: 'Your First Session', slug: 'getting-started/first-session' }, + ], + }, + { + label: 'Plugins', + link: '/plugins/', + icon: 'puzzle', + items: [ + { label: 'Plugin Overview', slug: 'plugins' }, + { + label: 'Core Plugins', + items: [ + { label: 'Agent System', slug: 'plugins/agent-system' }, + { label: 'Skill Engine', slug: 'plugins/skill-engine' }, + { label: 'Spec Workflow', slug: 'plugins/spec-workflow' }, + { label: 'Ticket Workflow', slug: 'plugins/ticket-workflow' }, + ], + }, + { + label: 'Quality & Safety', + items: [ + { label: 'Auto Code Quality', slug: 'plugins/auto-code-quality' }, + { label: 'Dangerous Command Blocker', slug: 'plugins/dangerous-command-blocker' }, + { label: 'Workspace Scope Guard', slug: 'plugins/workspace-scope-guard' }, + { label: 'Protected Files Guard', slug: 'plugins/protected-files-guard' }, + ], + }, + { + label: 'Session & Integration', + items: [ + { label: 'Session Context', slug: 'plugins/session-context' }, + { label: 'Notify Hook', slug: 'plugins/notify-hook' }, + { label: 'CodeForge LSP', slug: 'plugins/codeforge-lsp' }, + { label: 'Frontend Design', slug: 'plugins/frontend-design' }, + ], + }, + ], + }, + { + label: 'Features', + link: '/features/', + icon: 'star', + items: [ + { label: 'Features Overview', slug: 'features' }, + { label: 'AI Agents', slug: 'features/agents' }, + { label: 'Skills', slug: 'features/skills' }, + { label: 'CLI Tools', slug: 'features/tools' }, + { label: 'Code Intelligence', slug: 'features/code-intelligence' }, + ], + }, + { + label: 'Customization', + link: '/customization/', + icon: 'setting', + items: [ + { label: 'Customization Overview', slug: 'customization' }, + { label: 'Configuration', slug: 'customization/configuration' }, + { label: 'System Prompts', slug: 'customization/system-prompts' }, + { label: 'Rules', slug: 'customization/rules' }, + { label: 'Hooks', slug: 'customization/hooks' }, + ], + }, + { + label: 'Reference', + link: '/reference/', + icon: 'open-book', + items: [ + { label: 'Reference Overview', slug: 'reference' }, + { label: 'Changelog', slug: 'reference/changelog' }, + { label: 'Commands', slug: 'reference/commands' }, + { label: 'Environment Variables', slug: 'reference/environment' }, + { label: 'Architecture', slug: 'reference/architecture' }, + ], + }, + ], + ), + starlightImageZoom(), + starlightLinksValidator({ + errorOnRelativeLinks: false, + }), + starlightKbd({ + types: [ + { id: 'mac', label: 'macOS', detector: 'apple', default: false }, + { id: 'windows', label: 'Windows / Linux', detector: 'windows', default: true }, + ], + }), + starlightScrollToTop(), + starlightLlmsTxt(), + ], + }), + sitemap(), + ], + server: { + host: '0.0.0.0', + }, + vite: { + plugins: [tailwindcss()], + }, +}); diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 0000000..d7f114a --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,9303 @@ +{ + "name": "codeforge-docs", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "codeforge-docs", + "version": "0.1.0", + "dependencies": { + "@astrojs/sitemap": "^3.7.0", + "@astrojs/starlight": "^0.37.6", + "@astrojs/starlight-tailwind": "^4.0.2", + "@fontsource-variable/plus-jakarta-sans": "^5.2.8", + "@tailwindcss/vite": "^4.2.1", + "astro": "^5.17.3", + "astro-mermaid": "^1.3.1", + "sharp": "^0.34.5", + "starlight-image-zoom": "^0.13.2", + "starlight-kbd": "^0.3.0", + "starlight-links-validator": "^0.19.2", + "starlight-llms-txt": "^0.7.0", + "starlight-scroll-to-top": "^0.4.0", + "starlight-sidebar-topics": "^0.6.2", + "starlight-tags": "^0.4.0", + "tailwindcss": "^4.2.1" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "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/mdx": { + "version": "4.3.13", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.13.tgz", + "integrity": "sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==", + "license": "MIT", + "dependencies": { + "@astrojs/markdown-remark": "6.3.10", + "@mdx-js/mdx": "^3.1.1", + "acorn": "^8.15.0", + "es-module-lexer": "^1.7.0", + "estree-util-visit": "^2.0.0", + "hast-util-to-html": "^9.0.5", + "piccolore": "^0.1.3", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "remark-smartypants": "^3.0.2", + "source-map": "^0.7.6", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.3" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + }, + "peerDependencies": { + "astro": "^5.0.0" + } + }, + "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/sitemap": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.0.tgz", + "integrity": "sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA==", + "license": "MIT", + "dependencies": { + "sitemap": "^8.0.2", + "stream-replace-string": "^2.0.0", + "zod": "^3.25.76" + } + }, + "node_modules/@astrojs/starlight": { + "version": "0.37.6", + "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.37.6.tgz", + "integrity": "sha512-wQrKwH431q+8FsLBnNQeG+R36TMtEGxTQ2AuiVpcx9APcazvL3n7wVW8mMmYyxX0POjTnxlcWPkdMGR3Yj1L+w==", + "license": "MIT", + "dependencies": { + "@astrojs/markdown-remark": "^6.3.1", + "@astrojs/mdx": "^4.2.3", + "@astrojs/sitemap": "^3.3.0", + "@pagefind/default-ui": "^1.3.0", + "@types/hast": "^3.0.4", + "@types/js-yaml": "^4.0.9", + "@types/mdast": "^4.0.4", + "astro-expressive-code": "^0.41.1", + "bcp-47": "^2.1.0", + "hast-util-from-html": "^2.0.1", + "hast-util-select": "^6.0.2", + "hast-util-to-string": "^3.0.0", + "hastscript": "^9.0.0", + "i18next": "^23.11.5", + "js-yaml": "^4.1.0", + "klona": "^2.0.6", + "magic-string": "^0.30.17", + "mdast-util-directive": "^3.0.0", + "mdast-util-to-markdown": "^2.1.0", + "mdast-util-to-string": "^4.0.0", + "pagefind": "^1.3.0", + "rehype": "^13.0.1", + "rehype-format": "^5.0.0", + "remark-directive": "^3.0.0", + "ultrahtml": "^1.6.0", + "unified": "^11.0.5", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.2" + }, + "peerDependencies": { + "astro": "^5.5.0" + } + }, + "node_modules/@astrojs/starlight-tailwind": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/starlight-tailwind/-/starlight-tailwind-4.0.2.tgz", + "integrity": "sha512-SYN/6zq6hJO5tWqbQ2tWT9/jd8ubUkzkBCcF94vByC/ZJ20Mi5GPjFvAh89Yky/aIM+jXxT6W5q4p6l58GKHiQ==", + "license": "MIT", + "peerDependencies": { + "@astrojs/starlight": ">=0.34.0", + "tailwindcss": "^4.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/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.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/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT", + "peer": true + }, + "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/@chevrotain/cst-dts-gen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", + "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/gast": "11.1.1", + "@chevrotain/types": "11.1.1", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", + "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/types": "11.1.1", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", + "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@chevrotain/types": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", + "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@chevrotain/utils": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", + "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "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/@expressive-code/core": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.41.7.tgz", + "integrity": "sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.0.4", + "hast-util-select": "^6.0.2", + "hast-util-to-html": "^9.0.1", + "hast-util-to-text": "^4.0.1", + "hastscript": "^9.0.0", + "postcss": "^8.4.38", + "postcss-nested": "^6.0.1", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.1" + } + }, + "node_modules/@expressive-code/plugin-frames": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.41.7.tgz", + "integrity": "sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==", + "license": "MIT", + "dependencies": { + "@expressive-code/core": "^0.41.7" + } + }, + "node_modules/@expressive-code/plugin-shiki": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.41.7.tgz", + "integrity": "sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==", + "license": "MIT", + "dependencies": { + "@expressive-code/core": "^0.41.7", + "shiki": "^3.2.2" + } + }, + "node_modules/@expressive-code/plugin-text-markers": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.41.7.tgz", + "integrity": "sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==", + "license": "MIT", + "dependencies": { + "@expressive-code/core": "^0.41.7" + } + }, + "node_modules/@fontsource-variable/plus-jakarta-sans": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource-variable/plus-jakarta-sans/-/plus-jakarta-sans-5.2.8.tgz", + "integrity": "sha512-iQecBizIdZxezODNHzOn4SvvRMrZL/S8k4MEXGDynCmUrImVW0VmX+tIAMqnADwH4haXlHSXqMgU6+kcfBQJdw==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT", + "peer": true + }, + "node_modules/@iconify/utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", + "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "mlly": "^1.8.0" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "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/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", + "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", + "license": "MIT", + "peer": true, + "dependencies": { + "langium": "^4.0.0" + } + }, + "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" + ], + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/default-ui": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.4.0.tgz", + "integrity": "sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==", + "license": "MIT" + }, + "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" + ], + "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" + ], + "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" + ], + "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" + ], + "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.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.22.0.tgz", + "integrity": "sha512-iAlTtSDDbJiRpvgL5ugKEATDtHdUVkqgHDm/gbD2ZS9c88mx7G1zSYjjOxp5Qa0eaW0MAQosFRmJSk354PRoQA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.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.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.22.0.tgz", + "integrity": "sha512-jdKhfgW9CRtj3Tor0L7+yPwdG3CgP7W+ZEqSsojrMzCjD1e0IxIbwUMDDpYlVBlC08TACg4puwFGkZfLS+56Tw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.22.0.tgz", + "integrity": "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.22.0.tgz", + "integrity": "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz", + "integrity": "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.22.0.tgz", + "integrity": "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==", + "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/braces": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.5.tgz", + "integrity": "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==", + "license": "MIT" + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "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/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT", + "peer": true + }, + "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/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "license": "MIT" + }, + "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/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/micromatch": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.10.tgz", + "integrity": "sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ==", + "license": "MIT", + "dependencies": { + "@types/braces": "*" + } + }, + "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/node": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/picomatch": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-3.0.2.tgz", + "integrity": "sha512-n0i8TD3UDB7paoMMxA3Y65vUncFJXjcUf7lQY7YyKGl6031FNjfsLs6pdLFCy2GNFxItPJG8GvvpbZc2skH7WA==", + "license": "MIT" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true, + "peer": true + }, + "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/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.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-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "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/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/astro": { + "version": "5.17.3", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.17.3.tgz", + "integrity": "sha512-69dcfPe8LsHzklwj+hl+vunWUbpMB6pmg35mACjetxbJeUNNys90JaBM8ZiwsPK689SAj/4Zqb1ayaANls9/MA==", + "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-expressive-code": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.41.7.tgz", + "integrity": "sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==", + "license": "MIT", + "dependencies": { + "rehype-expressive-code": "^0.41.7" + }, + "peerDependencies": { + "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta" + } + }, + "node_modules/astro-mermaid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/astro-mermaid/-/astro-mermaid-1.3.1.tgz", + "integrity": "sha512-1+FjwayMSZLtFd+ofdu1+v8a902nN5wmPmjY2qb8tLiO96YlL65LbskiuUcyH6q9h0CdZCrkc5FimlaHZsMJsg==", + "license": "MIT", + "dependencies": { + "import-meta-resolve": "^4.2.0", + "mdast-util-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "peerDependencies": { + "@mermaid-js/layout-elk": "^0.2.0", + "astro": "^4.0.0 || ^5.0.0", + "mermaid": "^10.0.0 || ^11.0.0" + }, + "peerDependenciesMeta": { + "@mermaid-js/layout-elk": { + "optional": true + } + } + }, + "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/bcp-47": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz", + "integrity": "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/bcp-47-match": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", + "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "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/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", + "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/cst-dts-gen": "11.1.1", + "@chevrotain/gast": "11.1.1", + "@chevrotain/regexp-to-ast": "11.1.1", + "@chevrotain/types": "11.1.1", + "@chevrotain/utils": "11.1.1", + "lodash-es": "4.17.23" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "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/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "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/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT", + "peer": true + }, + "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/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "peer": true, + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "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-selector-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz", + "integrity": "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.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/cytoscape": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", + "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "peer": true, + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT", + "peer": true + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "peer": true, + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "peer": true, + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "peer": true, + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC", + "peer": true + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", + "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "license": "MIT", + "peer": true + }, + "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/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "peer": true, + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "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/direction": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", + "license": "MIT", + "bin": { + "direction": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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/dompurify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", + "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "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.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "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/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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/expressive-code": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/expressive-code/-/expressive-code-0.41.7.tgz", + "integrity": "sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==", + "license": "MIT", + "dependencies": { + "@expressive-code/core": "^0.41.7", + "@expressive-code/plugin-frames": "^0.41.7", + "@expressive-code/plugin-shiki": "^0.41.7", + "@expressive-code/plugin-text-markers": "^0.41.7" + } + }, + "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/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.2.tgz", + "integrity": "sha512-piJxbLnkD9Xcyi7dWJRnqszEURixe7CrF/efBfbffe2DPyabmuIuqraruY8cXTs19QoM8VJzx47BDRVNXETM7Q==", + "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/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT", + "peer": true + }, + "node_modules/has-flag": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", + "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hast-util-embedded": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz", + "integrity": "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-is-element": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-format": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hast-util-format/-/hast-util-format-1.1.0.tgz", + "integrity": "sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-embedded": "^3.0.0", + "hast-util-minify-whitespace": "^1.0.0", + "hast-util-phrasing": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "html-whitespace-sensitive-tag-names": "^3.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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-has-property": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-body-ok-link": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.1.tgz", + "integrity": "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.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-minify-whitespace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hast-util-minify-whitespace/-/hast-util-minify-whitespace-1.0.1.tgz", + "integrity": "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-embedded": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "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-phrasing": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz", + "integrity": "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-embedded": "^3.0.0", + "hast-util-has-property": "^3.0.0", + "hast-util-is-body-ok-link": "^3.0.0", + "hast-util-is-element": "^3.0.0" + }, + "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-select": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz", + "integrity": "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "bcp-47-match": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "css-selector-parser": "^3.0.0", + "devlop": "^1.0.0", + "direction": "^2.0.0", + "hast-util-has-property": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "nth-check": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "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-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-mdast": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/hast-util-to-mdast/-/hast-util-to-mdast-10.1.2.tgz", + "integrity": "sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-phrasing": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "hast-util-to-text": "^4.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-minify-whitespace": "^6.0.0", + "trim-trailing-lines": "^2.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0" + }, + "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-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.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/html-whitespace-sensitive-tag-names": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-whitespace-sensitive-tag-names/-/html-whitespace-sensitive-tag-names-3.0.1.tgz", + "integrity": "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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/i18next": { + "version": "23.16.8", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz", + "integrity": "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "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-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "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/katex": { + "version": "0.16.33", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.33.tgz", + "integrity": "sha512-q3N5u+1sY9Bu7T4nlXoiRBXWfwSefNGoKeOwekV+gw0cAXQlz2Ww6BLcmBxVDeXBMUDQv6fK5bcNaJLxob3ZQA==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "peer": true, + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "peer": true + }, + "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/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/langium": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", + "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "chevrotain": "~11.1.1", + "chevrotain-allstar": "~0.3.1", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.1.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT", + "peer": true + }, + "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/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "license": "MIT", + "peer": true + }, + "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-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "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-directive": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", + "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "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-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "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.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "license": "CC0-1.0" + }, + "node_modules/mermaid": { + "version": "11.12.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", + "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.1", + "@mermaid-js/parser": "^1.0.0", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.3", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.13", + "dayjs": "^1.11.18", + "dompurify": "^3.2.5", + "katex": "^0.16.22", + "khroma": "^2.1.0", + "lodash-es": "^4.17.23", + "marked": "^16.2.1", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.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-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "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-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "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-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "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/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/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/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "license": "MIT", + "peer": true, + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "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==", + "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-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT", + "peer": true + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT", + "peer": true + }, + "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/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT", + "peer": true + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "peer": true, + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "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/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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-expressive-code": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/rehype-expressive-code/-/rehype-expressive-code-0.41.7.tgz", + "integrity": "sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==", + "license": "MIT", + "dependencies": { + "expressive-code": "^0.41.7" + } + }, + "node_modules/rehype-format": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/rehype-format/-/rehype-format-5.0.1.tgz", + "integrity": "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-format": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-minify-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-6.0.2.tgz", + "integrity": "sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-minify-whitespace": "^1.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-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-remark": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-remark/-/rehype-remark-10.0.1.tgz", + "integrity": "sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "hast-util-to-mdast": "^10.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "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-directive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz", + "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.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-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.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/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense", + "peer": true + }, + "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/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT", + "peer": true + }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "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.22.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.22.0.tgz", + "integrity": "sha512-LBnhsoYEe0Eou4e1VgJACes+O6S6QC0w71fCSp5Oya79inkwkm15gQ1UF6VtQ8j/taMDh79hAB49WUk8ALQW3g==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.22.0", + "@shikijs/engine-javascript": "3.22.0", + "@shikijs/engine-oniguruma": "3.22.0", + "@shikijs/langs": "3.22.0", + "@shikijs/themes": "3.22.0", + "@shikijs/types": "3.22.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/sitemap": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.2.tgz", + "integrity": "sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ==", + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.4.1" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "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": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "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/starlight-image-zoom": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/starlight-image-zoom/-/starlight-image-zoom-0.13.2.tgz", + "integrity": "sha512-fDJrx+UZXhkbhEeXKoRogTKAYtrYVJPw6wmSUI3nHUTA0vuRM6EI//2Z8bzv3Ecvz0pHKD1vAxtS01mLyessBA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx-jsx": "^3.1.3", + "rehype-raw": "^7.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@astrojs/starlight": ">=0.32.0" + } + }, + "node_modules/starlight-kbd": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/starlight-kbd/-/starlight-kbd-0.3.0.tgz", + "integrity": "sha512-bhG1kWGEXCkuV8pkYW6sWEVmwD2bnpQpVIxq4QDJp7tLsprAbIKnD7RKFCP/QtITfwaVgKq3uMNK0+p4TUAgGg==", + "license": "MIT", + "engines": { + "node": ">=18.17.1" + }, + "peerDependencies": { + "@astrojs/starlight": ">=0.32.0" + } + }, + "node_modules/starlight-links-validator": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/starlight-links-validator/-/starlight-links-validator-0.19.2.tgz", + "integrity": "sha512-IHeK3R78fsmv53VfRkGbXkwK1CQEUBHM9QPzBEyoAxjZ/ssi5gjV+F4oNNUppTR48iPp+lEY0MTAmvkX7yNnkw==", + "license": "MIT", + "dependencies": { + "@types/picomatch": "^3.0.1", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", + "hast-util-has-property": "^3.0.0", + "is-absolute-url": "^4.0.1", + "kleur": "^4.1.5", + "mdast-util-mdx-jsx": "^3.1.3", + "mdast-util-to-string": "^4.0.0", + "picomatch": "^4.0.2", + "terminal-link": "^5.0.0", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=18.17.1" + }, + "peerDependencies": { + "@astrojs/starlight": ">=0.32.0", + "astro": ">=5.1.5" + } + }, + "node_modules/starlight-links-validator/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/starlight-llms-txt": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/starlight-llms-txt/-/starlight-llms-txt-0.7.0.tgz", + "integrity": "sha512-KAay6JLXqB0GiNQ481z3Z/h/y4xeAU55TUGLz+npjxcRvN3h/7rDxjmyLiphZF8xfoqqSTduQPanl5Ct4Je6kA==", + "license": "MIT", + "dependencies": { + "@astrojs/mdx": "^4.3.13", + "@types/hast": "^3.0.4", + "@types/micromatch": "^4.0.10", + "github-slugger": "^2.0.0", + "hast-util-select": "^6.0.4", + "micromatch": "^4.0.8", + "rehype-parse": "^9.0.1", + "rehype-remark": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-stringify": "^11.0.0", + "unified": "^11.0.5", + "unist-util-remove": "^4.0.0" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + }, + "peerDependencies": { + "@astrojs/starlight": ">=0.31", + "astro": "^5.15.9" + } + }, + "node_modules/starlight-scroll-to-top": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/starlight-scroll-to-top/-/starlight-scroll-to-top-0.4.0.tgz", + "integrity": "sha512-lxsW5Sv+oKCI8CYZQ6Ue957cExiHMozK73LmmbsvpBKWryW+AKU4OXmX/1bTQNx+mVLZcpm2qTwKa1KX5VdEaQ==", + "license": "MIT", + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + }, + "peerDependencies": { + "@astrojs/starlight": ">=0.35" + } + }, + "node_modules/starlight-sidebar-topics": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/starlight-sidebar-topics/-/starlight-sidebar-topics-0.6.2.tgz", + "integrity": "sha512-SNCTUZS/hcVor0ZcaXbaSVU37+V+qtvzNirkvnOg3Mqu/awuGpthkH5+uKpiZqWxLffp6TrOlsv5E5QsxrndNg==", + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@astrojs/starlight": ">=0.32.0" + } + }, + "node_modules/starlight-tags": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/starlight-tags/-/starlight-tags-0.4.0.tgz", + "integrity": "sha512-CX8Wh9J2rT+SzlPwKlWtb/qvyqIDxHgjgA7VYt/Vj8iSujgDXMMjQ2GyqERWz0i6PuINXSnVVUGqDrJuwh4p5A==", + "license": "MIT", + "dependencies": { + "js-yaml": "^4.1.1" + }, + "engines": { + "node": ">=18.17.1" + }, + "peerDependencies": { + "@astrojs/starlight": ">=0.35.0" + } + }, + "node_modules/stream-replace-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", + "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", + "license": "MIT" + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT", + "peer": true + }, + "node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-hyperlinks": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.4.0.tgz", + "integrity": "sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==", + "license": "MIT", + "dependencies": { + "has-flag": "^5.0.1", + "supports-color": "^10.2.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/svgo": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", + "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", + "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.4.1" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/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/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/terminal-link": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-5.0.0.tgz", + "integrity": "sha512-qFAy10MTMwjzjU8U16YS4YoZD+NQLHzLssFMNqgravjbvIPNiqkGFR4yjhJfmY9R5OFU7+yHxc6y+uGHkKwLRA==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^4.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "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/trim-trailing-lines": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-2.1.0.tgz", + "integrity": "sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==", + "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/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.10" + } + }, + "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/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "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-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-4.0.0.tgz", + "integrity": "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==", + "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-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/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "peer": true, + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "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/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "peer": true, + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "peer": true, + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT", + "peer": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT", + "peer": true + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT", + "peer": 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 0000000..b82f309 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,31 @@ +{ + "name": "codeforge-docs", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "sync": "node scripts/sync-changelog.mjs", + "dev": "node scripts/sync-changelog.mjs && astro dev --host 0.0.0.0", + "build": "node scripts/sync-changelog.mjs && astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/sitemap": "^3.7.0", + "@astrojs/starlight": "^0.37.6", + "@astrojs/starlight-tailwind": "^4.0.2", + "@fontsource-variable/plus-jakarta-sans": "^5.2.8", + "@tailwindcss/vite": "^4.2.1", + "astro": "^5.17.3", + "astro-mermaid": "^1.3.1", + "sharp": "^0.34.5", + "starlight-image-zoom": "^0.13.2", + "starlight-kbd": "^0.3.0", + "starlight-links-validator": "^0.19.2", + "starlight-llms-txt": "^0.7.0", + "starlight-scroll-to-top": "^0.4.0", + "starlight-sidebar-topics": "^0.6.2", + "starlight-tags": "^0.4.0", + "tailwindcss": "^4.2.1" + } +} diff --git a/docs/public/apple-touch-icon.png b/docs/public/apple-touch-icon.png new file mode 100644 index 0000000..aba7e44 Binary files /dev/null and b/docs/public/apple-touch-icon.png differ diff --git a/docs/public/favicon.png b/docs/public/favicon.png new file mode 100644 index 0000000..a0e72ca Binary files /dev/null and b/docs/public/favicon.png differ diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg new file mode 100644 index 0000000..a80e613 --- /dev/null +++ b/docs/public/favicon.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/og-image.png b/docs/public/og-image.png new file mode 100644 index 0000000..c62bcf8 Binary files /dev/null and b/docs/public/og-image.png differ diff --git a/docs/scripts/sync-changelog.mjs b/docs/scripts/sync-changelog.mjs new file mode 100644 index 0000000..add9447 --- /dev/null +++ b/docs/scripts/sync-changelog.mjs @@ -0,0 +1,78 @@ +/** + * Syncs .devcontainer/CHANGELOG.md into the docs content collection. + * + * Runs before `astro dev` and `astro build` so the docs site always + * reflects the canonical changelog. The source file is the single + * source of truth — never edit the generated docs page directly. + */ + +import { readFileSync, writeFileSync } from 'node:fs'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const source = resolve(__dirname, '../../.devcontainer/CHANGELOG.md'); +const dest = resolve(__dirname, '../src/content/docs/reference/changelog.md'); + +const content = readFileSync(source, 'utf-8'); + +// Strip the H1 heading — Starlight generates one from the frontmatter title +const body = content.replace(/^# .+\n+/, ''); + +// Convert [vX.Y.Z] link-style headings to plain ## vX.Y.Z headings +// Source uses ## [v1.14.0] - 2026-02-24, docs need ## v1.14.0 +const cleaned = body.replace(/^(##) \[v([\d.]+)\] - (\d{4}-\d{2}-\d{2})/gm, '$1 v$2\n\n**Release date:** $3'); + +const frontmatter = `--- +title: Changelog +description: Complete version history for every CodeForge release — features, fixes, and migration guides. +sidebar: + order: 1 +--- + +:::note[Auto-Generated] +This page mirrors [\`.devcontainer/CHANGELOG.md\`](https://github.com/AnExiledDev/CodeForge/blob/main/.devcontainer/CHANGELOG.md) and is regenerated on every build. Do not edit directly — update the source file instead. +::: + +## Versioning Policy + +CodeForge follows semantic versioning: + +- **Major** (X.0.0) — Breaking changes that require migration steps +- **Minor** (0.X.0) — New features and enhancements, backward compatible +- **Patch** (0.0.X) — Bug fixes with no feature changes + +Breaking changes are rare. Most releases are minor versions that add new plugins, skills, or tools without requiring any user action beyond updating. + +## Update Process + +\`\`\`bash +# Update to latest version +npx codeforge-dev@latest + +# Update to a specific version +npx codeforge-dev@1.14.0 +\`\`\` + +After updating, rebuild your DevContainer to apply changes: + +1. Open the VS Code command palette (\`Ctrl+Shift+P\` / \`Cmd+Shift+P\`) +2. Select **Dev Containers: Rebuild Container** + +:::tip[Non-Breaking Updates] +For minor and patch updates, you can usually just rebuild the container. Check the changelog entries below for any migration notes before upgrading across multiple major versions. +::: + +## Related + +- [Installation](../getting-started/installation/) — initial setup and update instructions +- [Architecture](./architecture/) — system design context for understanding changes + +--- + +## Version History + +`; + +writeFileSync(dest, frontmatter + cleaned); +console.log('✓ Changelog synced from .devcontainer/CHANGELOG.md'); diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png new file mode 100644 index 0000000..984348a Binary files /dev/null and b/docs/src/assets/logo.png differ diff --git a/docs/src/assets/logo.svg b/docs/src/assets/logo.svg new file mode 100644 index 0000000..245d70d --- /dev/null +++ b/docs/src/assets/logo.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/components/FeatureCard.astro b/docs/src/components/FeatureCard.astro new file mode 100644 index 0000000..5f3e392 --- /dev/null +++ b/docs/src/components/FeatureCard.astro @@ -0,0 +1,44 @@ +--- +interface Props { + title: string; + description: string; + icon: string; +} + +const { title, description, icon } = Astro.props; +--- + +
+
+

{title}

+

{description}

+
+ + diff --git a/docs/src/components/Header.astro b/docs/src/components/Header.astro new file mode 100644 index 0000000..742edd0 --- /dev/null +++ b/docs/src/components/Header.astro @@ -0,0 +1,110 @@ +--- +/** + * Custom Header — extends Starlight's default Header with a "Docs" button. + */ +import config from 'virtual:starlight/user-config'; + +import LanguageSelect from 'virtual:starlight/components/LanguageSelect'; +import Search from 'virtual:starlight/components/Search'; +import SiteTitle from 'virtual:starlight/components/SiteTitle'; +import SocialIcons from 'virtual:starlight/components/SocialIcons'; +import ThemeSelect from 'virtual:starlight/components/ThemeSelect'; + +const shouldRenderSearch = + config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro'; +--- + +
+
+ +
+
+ {shouldRenderSearch && } +
+
+ Docs + + + +
+
+ + diff --git a/docs/src/components/Hero.astro b/docs/src/components/Hero.astro new file mode 100644 index 0000000..dfb186a --- /dev/null +++ b/docs/src/components/Hero.astro @@ -0,0 +1,384 @@ +--- +/** + * Custom Hero component — overrides Starlight's built-in Hero. + * Full-width ember/charcoal hero with animated particles, terminal preview, + * stats bar, and a feature grid below the fold. + * + * Receives Starlight's Hero props but renders entirely custom content. + */ +import FeatureCard from './FeatureCard.astro'; +import InstallCommand from './InstallCommand.astro'; + +/* Accept Starlight's props to satisfy the component override contract */ +const _props = Astro.props; +--- + +
+ {/* ---- Ember particles (CSS-only, hidden under prefers-reduced-motion) ---- */} + + + + + + + + + + + + + + + + + {/* ---- Content ---- */} +
+

+ Your AI dev environment, battle-tested. +

+ +

+ The complete Claude Code setup — 12 plugins, 21 tools, + 17 AI agents. Drop it into any project and start building. +

+ + {/* ---- CTA buttons ---- */} + + + {/* ---- Terminal preview ---- */} +
+ +
+ + {/* ---- Stats bar (pill style) ---- */} +
+ 12 Plugins + 21 Tools + 17 AI Agents + 21 Skills +
+
+
+ +{/* ---- Feature grid (below the hero fold) ---- */} +
+
+ + + + +
+
+ +{/* ---- How it works (below feature grid) ---- */} +
+

Get running in 60 seconds

+
+
+
1
+

Install

+

Run npx codeforge-dev in your project. One command sets up the entire DevContainer.

+
+ +
+
2
+

Open

+

Reopen in the DevContainer. VS Code, Codespaces, or any devcontainer host.

+
+ +
+
3
+

Build

+

Type cc to launch Claude Code with 17 agents, 12 plugins, and full quality automation.

+
+
+
+ + diff --git a/docs/src/components/InstallCommand.astro b/docs/src/components/InstallCommand.astro new file mode 100644 index 0000000..01d8c8f --- /dev/null +++ b/docs/src/components/InstallCommand.astro @@ -0,0 +1,31 @@ +--- +/* Terminal-style install command display. Self-contained, no props needed. */ +--- + +
+
+ + + +
+
+ $ + npx codeforge-dev +
+
+ + diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts new file mode 100644 index 0000000..d9ee8c9 --- /dev/null +++ b/docs/src/content.config.ts @@ -0,0 +1,7 @@ +import { defineCollection } from 'astro:content'; +import { docsLoader } from '@astrojs/starlight/loaders'; +import { docsSchema } from '@astrojs/starlight/schema'; + +export const collections = { + docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), +}; diff --git a/docs/src/content/docs/customization/configuration.md b/docs/src/content/docs/customization/configuration.md new file mode 100644 index 0000000..ccf2616 --- /dev/null +++ b/docs/src/content/docs/customization/configuration.md @@ -0,0 +1,238 @@ +--- +title: Configuration +description: CodeForge configuration through settings.json, environment variables, and feature flags. +sidebar: + order: 2 +--- + +CodeForge configuration is spread across three files that each control a different aspect of the environment: `settings.json` for Claude Code behavior, `devcontainer.json` for container setup, and `file-manifest.json` for config file deployment. + +## settings.json + +The primary configuration file lives at `.devcontainer/config/defaults/settings.json`. It is deployed to `.claude/settings.json` on every container start and controls Claude Code's runtime behavior. + +### Core Settings + +```json +{ + "model": "opus", + "effortLevel": "high", + "cleanupPeriodDays": 60, + "autoCompact": true, + "alwaysThinkingEnabled": true, + "teammateMode": "auto", + "includeCoAuthoredBy": false +} +``` + +| Setting | Purpose | Default | +|---------|---------|---------| +| `model` | Default Claude model (`opus`, `sonnet`, `haiku`) | `opus` | +| `effortLevel` | Response effort (`low`, `medium`, `high`) | `high` | +| `cleanupPeriodDays` | Days before old session data is cleaned up | `60` | +| `autoCompact` | Automatically compact context when it gets long | `true` | +| `alwaysThinkingEnabled` | Enable extended thinking for all responses | `true` | +| `teammateMode` | Agent Teams mode (`auto`, `manual`, `off`) | `auto` | + +### Environment Variables Block + +The `env` block sets environment variables that configure Claude Code internals: + +```json +{ + "env": { + "ANTHROPIC_MODEL": "claude-opus-4-6", + "BASH_DEFAULT_TIMEOUT_MS": "240000", + "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "64000", + "MAX_THINKING_TOKENS": "63999", + "CLAUDE_CODE_SHELL": "zsh", + "CLAUDE_CODE_EFFORT_LEVEL": "high", + "CLAUDE_CODE_ENABLE_TASKS": "true", + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" + } +} +``` + +See [Environment Variables](../reference/environment/) for the complete list of available variables and their effects. + +### Permissions + +The `permissions` block controls what Claude Code can do without asking: + +```json +{ + "permissions": { + "allow": ["Read(/workspaces/*)", "WebFetch(domain:*)"], + "deny": [], + "ask": [], + "defaultMode": "plan", + "additionalDirectories": [] + } +} +``` + +- **allow** -- Operations that proceed without user confirmation +- **deny** -- Operations that are always blocked +- **ask** -- Operations that prompt for confirmation each time +- **defaultMode** -- Starting permission mode (`plan` means Claude proposes before acting) + +### Plugin Toggles + +The `enabledPlugins` section controls which plugins are active: + +```json +{ + "enabledPlugins": { + "agent-system@devs-marketplace": true, + "skill-engine@devs-marketplace": true, + "spec-workflow@devs-marketplace": true, + "session-context@devs-marketplace": true, + "auto-code-quality@devs-marketplace": true, + "dangerous-command-blocker@devs-marketplace": true, + "protected-files-guard@devs-marketplace": true, + "workspace-scope-guard@devs-marketplace": true, + "notify-hook@devs-marketplace": true, + "ticket-workflow@devs-marketplace": true, + "codeforge-lsp@devs-marketplace": true, + "frontend-design@claude-plugins-official": true + } +} +``` + +Set any plugin to `false` to disable it. The plugin remains installed but its hooks will not fire. + +### Status Line + +The `statusLine` block configures the terminal status bar: + +```json +{ + "statusLine": { + "type": "command", + "command": "/usr/local/bin/ccstatusline-wrapper" + } +} +``` + +## file-manifest.json + +The file manifest at `.devcontainer/config/file-manifest.json` controls which configuration files are deployed to `.claude/` and how they are updated. Each entry specifies a source file, a destination, and an overwrite strategy: + +```json +[ + { + "src": "defaults/settings.json", + "dest": "${CLAUDE_CONFIG_DIR}", + "enabled": true, + "overwrite": "if-changed" + }, + { + "src": "defaults/main-system-prompt.md", + "dest": "${CLAUDE_CONFIG_DIR}", + "enabled": true, + "overwrite": "if-changed" + }, + { + "src": "defaults/rules/spec-workflow.md", + "dest": "${CLAUDE_CONFIG_DIR}/rules", + "enabled": true, + "overwrite": "if-changed" + } +] +``` + +### Overwrite Modes + +| Mode | Behavior | +|------|----------| +| `if-changed` | Overwrites only when the source file's SHA-256 hash differs from the deployed copy. This is the default and recommended mode. | +| `always` | Overwrites on every container start, regardless of changes | +| `never` | Copies only if the destination does not exist. User edits are always preserved. | + +:::tip[Preserving Your Edits] +If you customize a deployed file (like `settings.json` or the system prompt) and want your changes to survive container rebuilds, change its overwrite mode to `"never"` in `file-manifest.json`. +::: + +### Adding a New Config File + +To deploy a new file to `.claude/` automatically: + +1. Place the file in `.devcontainer/config/defaults/` +2. Add an entry to `file-manifest.json` +3. Rebuild the container + +## devcontainer.json + +The DevContainer configuration at `.devcontainer/devcontainer.json` defines the container itself: base image, installed features, VS Code settings, port forwarding, and resource limits. + +### Base Image and Resources + +```json +{ + "image": "mcr.microsoft.com/devcontainers/python:3.14", + "runArgs": ["--memory=6g", "--memory-swap=12g"], + "remoteUser": "vscode", + "containerUser": "vscode" +} +``` + +### Feature Installation + +DevContainer features install runtimes and tools. CodeForge pins external features to specific versions for reproducibility: + +```json +{ + "features": { + "ghcr.io/devcontainers/features/node:1.7.1": { "version": "lts" }, + "ghcr.io/devcontainers/features/rust:1.5.0": { "version": "latest" }, + "ghcr.io/anthropics/devcontainer-features/claude-code:1.0.5": {}, + "./features/ruff": { "version": "latest" }, + "./features/ccms": {} + } +} +``` + +:::tip[Disabling a Feature] +Any local feature (those starting with `./features/`) can be disabled by setting `"version": "none"`. The feature's install script will skip entirely. +::: + +### Secrets + +Optional secrets can be declared for VS Code Codespaces or other DevContainer hosts: + +```json +{ + "secrets": { + "GH_TOKEN": { + "description": "GitHub Personal Access Token (optional)", + "documentationUrl": "https://github.com/settings/tokens" + }, + "NPM_TOKEN": { + "description": "NPM auth token (optional)" + }, + "GH_USERNAME": { + "description": "GitHub username for git config (optional)" + }, + "GH_EMAIL": { + "description": "GitHub email for git config (optional)" + } + } +} +``` + +## Configuration Precedence + +When the same setting is defined at multiple levels, the most specific value wins: + +1. **Environment variables** (per-session or shell profile) -- highest precedence +2. **Project settings** (`.devcontainer/config/` in the current project) +3. **Default settings** (shipped with CodeForge) + +For example, setting `ANTHROPIC_MODEL=claude-sonnet-4-5-20250929` in your shell overrides whatever is configured in `settings.json`. + +## Related + +- [Environment Variables](../reference/environment/) -- complete env var reference +- [System Prompts](./system-prompts/) -- configure Claude's behavioral guidelines +- [Plugins](../plugins/) -- per-plugin configuration options +- [Architecture](../reference/architecture/) -- how configuration layers compose at runtime diff --git a/docs/src/content/docs/customization/hooks.md b/docs/src/content/docs/customization/hooks.md new file mode 100644 index 0000000..899095e --- /dev/null +++ b/docs/src/content/docs/customization/hooks.md @@ -0,0 +1,291 @@ +--- +title: Hooks +description: The hook system that lets plugins and custom scripts run at specific points in the Claude Code lifecycle. +sidebar: + order: 5 +--- + +Hooks are scripts that execute at specific points during a Claude Code session. They let plugins validate commands before they run, inject context after tool use, run quality checks when Claude finishes a turn, and respond to team events. Hooks are the primary mechanism for extending Claude Code without modifying it. + +## Hook Points + +CodeForge uses eight hook points, each serving a different purpose in the session lifecycle: + +### PreToolUse + +Fires **before** a tool executes. Used for validation and gating. + +**Common uses:** Block dangerous shell commands, enforce workspace scope, protect critical files, validate file paths, redirect agent types. + +**Return behavior:** The script exits with code 0 to allow the tool, or code 2 to block it with an error message. + +**Example from CodeForge:** The dangerous-command-blocker checks every Bash command against a list of destructive patterns (like `rm -rf /` or `git push --force main`) and blocks matches before they execute. + +### PostToolUse + +Fires **after** a tool executes successfully. Used for context injection and file tracking. + +**Common uses:** Collect edited files for batch processing, validate syntax of written files, suggest relevant skills, inject working directory context. + +**Return behavior:** The script can return context to inject into the conversation via `additionalContext`, or return nothing for silent observation. + +**Example from CodeForge:** The auto-code-quality plugin tracks every file edited via `Edit` or `Write` tools, then batches them for formatting and linting at the next Stop point. + +### Stop + +Fires **when Claude finishes a turn** and returns control to the user. Used for quality assurance and reminders. + +**Common uses:** Batch format all edited files, run linters, execute affected tests, remind about uncommitted changes, check if specs need updating, send desktop notifications. + +**Return behavior:** Context injected via `additionalContext` appears in Claude's next turn. Advisory hooks (like the test runner) provide information without blocking. + +**Example from CodeForge:** At every Stop, the auto-code-quality plugin formats all edited files (Ruff, Biome, gofmt, shfmt, dprint, rustfmt), runs linters (Pyright, Ruff, Biome, ShellCheck, go vet, hadolint, clippy), and then runs affected tests. + +### SessionStart + +Fires **when a new session begins**. Used for initial context loading. + +**Common uses:** Inject git repository state (branch, status, recent commits), harvest TODO/FIXME comments from the codebase. + +### SubagentStart + +Fires **when a subagent is spawned**. Used for subagent configuration. + +**Common uses:** Inject the current working directory into subagent context. + +### TeammateIdle + +Fires **when a teammate agent goes idle** in a team session. Used for quality gates. + +**Common uses:** Check whether the teammate has incomplete tasks before allowing shutdown. + +### TaskCompleted + +Fires **when a task is marked complete** in a team session. Used for verification. + +**Common uses:** Run the test suite to verify the completed task has not broken anything. + +### UserPromptSubmit + +Fires **when the user sends a prompt**, before Claude processes it. Used for context enrichment. + +**Common uses:** Auto-suggest relevant skills based on prompt content, fetch linked GitHub issues/PRs from `#123` references, inject contextual information. + +**Return behavior:** The script can return `additionalContext` to inject information into Claude's context before it processes the user's message. + +**Example from CodeForge:** The skill-engine's `skill-suggester.py` matches your prompt against keyword patterns and suggests relevant skills. The ticket-workflow's `ticket-linker.py` detects GitHub issue references and fetches their details. + +## Hook Registration + +Hooks are registered in a `hooks.json` file within a plugin's `hooks/` directory. Here is the structure from the session-context plugin: + +```json +{ + "description": "Context injection at session boundaries", + "hooks": { + "SessionStart": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/git-state-injector.py", + "timeout": 10 + }, + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/todo-harvester.py", + "timeout": 8 + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/commit-reminder.py", + "timeout": 8 + } + ] + } + ] + } +} +``` + +### Registration Fields + +| Field | Description | Required | +|-------|-------------|----------| +| `type` | Execution type (always `"command"` for script-based hooks) | Yes | +| `command` | Shell command to execute. Use `${CLAUDE_PLUGIN_ROOT}` to reference the plugin directory. | Yes | +| `timeout` | Maximum execution time in seconds. The hook is killed if it exceeds this limit. | Yes | +| `matcher` | Tool name filter -- only fires for matching tools. Use `\|` to match multiple tools (e.g., `Edit\|Write`). Empty string matches all tools. Only relevant for PreToolUse, PostToolUse, and SubagentStart. | No | + +:::tip[Set Reasonable Timeouts] +Hooks run synchronously in the Claude Code pipeline. A slow hook delays every tool use. Keep PreToolUse and PostToolUse hooks under 5 seconds. Stop hooks can be longer (up to 60 seconds) since they run at turn boundaries. +::: + +## Hook Scripts + +Hook scripts are typically Python files that receive context via stdin (JSON) and communicate results via stdout and exit codes. + +### Input Format + +Scripts receive a JSON object on stdin with context about the current tool use: + +```json +{ + "tool_name": "Bash", + "tool_input": { + "command": "git status" + }, + "session_id": "abc-123", + "cwd": "/workspaces/projects/MyProject" +} +``` + +The exact fields depend on the hook point and which tool triggered it. + +### Output Format + +Scripts communicate results in two ways: + +**Exit codes** (PreToolUse only): +- `0` -- Allow the tool to proceed +- `2` -- Block the tool and show the error message from stdout + +**Stdout JSON** (all hook points): +```json +{ + "decision": "allow", + "message": "Optional context to inject", + "additionalContext": "Text that appears in Claude's context" +} +``` + +:::caution[Fail Closed for Safety Hooks] +Safety-critical hooks (like the dangerous-command-blocker) should fail closed: if JSON parsing fails or an unexpected error occurs, exit with code 2 to block the operation rather than code 0 to allow it. +::: + +## Creating Your First Hook + +Here is a step-by-step example of creating a PreToolUse hook that blocks shell commands containing `sudo`: + +### Step 1: Write the Script + +Create `scripts/block-sudo.py` in your plugin directory: + +```python +#!/usr/bin/env python3 +"""Block any bash command that uses sudo.""" + +import json +import sys + +def main(): + try: + data = json.load(sys.stdin) + except (json.JSONDecodeError, EOFError): + # Fail closed: block if we can't parse the input + print(json.dumps({ + "decision": "block", + "message": "Hook error: could not parse input" + })) + sys.exit(2) + + tool_name = data.get("tool_name", "") + tool_input = data.get("tool_input", {}) + + if tool_name != "Bash": + sys.exit(0) + + command = tool_input.get("command", "") + if "sudo" in command.split(): + print(json.dumps({ + "decision": "block", + "message": "Blocked: sudo is not allowed in this environment" + })) + sys.exit(2) + + sys.exit(0) + +if __name__ == "__main__": + main() +``` + +### Step 2: Register the Hook + +Add the hook to your plugin's `hooks/hooks.json`: + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/block-sudo.py", + "timeout": 3 + } + ] + } + ] + } +} +``` + +### Step 3: Test It + +Start a Claude Code session and try a command with `sudo`. The hook should block it with your custom message. + +## Hook Execution Order + +When multiple plugins register hooks for the same point: + +1. Hooks execute in plugin registration order (as listed in `settings.json` `enabledPlugins`) +2. **PreToolUse:** If _any_ hook blocks (exit 2), the tool does not execute. Remaining hooks are skipped. +3. **PostToolUse and Stop:** All hooks execute regardless of individual results. One hook's failure does not prevent others from running. +4. **Within a plugin:** Hooks listed in the same array execute sequentially in order. + +## Built-in Hook Summary + +Here is a quick reference of all hooks registered by CodeForge's default plugins: + +| Plugin | Hook Point | Script | Purpose | +|--------|-----------|--------|---------| +| agent-system | PreToolUse (Task) | `redirect-builtin-agents.py` | Swap built-in agents for enhanced custom agents | +| agent-system | SubagentStart | `inject-cwd.py` | Inject working directory into subagent context | +| agent-system | TeammateIdle | `teammate-idle-check.py` | Check incomplete tasks before teammate shutdown | +| agent-system | TaskCompleted | `task-completed-check.py` | Run test suite after task completion | +| auto-code-quality | PostToolUse (Edit\|Write) | `collect-edited-files.py` | Track edited files for batch processing | +| auto-code-quality | PostToolUse (Edit\|Write) | `syntax-validator.py` | Validate syntax of written files | +| auto-code-quality | Stop | `format-on-stop.py` | Batch format all edited files | +| auto-code-quality | Stop | `lint-file.py` | Batch lint all edited files | +| auto-code-quality | Stop | `advisory-test-runner.py` | Run affected tests | +| session-context | SessionStart | `git-state-injector.py` | Inject git branch, status, recent commits | +| session-context | SessionStart | `todo-harvester.py` | Surface TODO/FIXME comments | +| session-context | Stop | `commit-reminder.py` | Remind about uncommitted changes | +| dangerous-command-blocker | PreToolUse (Bash) | `block-dangerous.py` | Block destructive bash commands | +| protected-files-guard | PreToolUse (Edit\|Write) | `guard-protected.py` | Block edits to sensitive files | +| protected-files-guard | PreToolUse (Bash) | `guard-protected-bash.py` | Block bash writes to sensitive paths | +| workspace-scope-guard | PreToolUse (Read\|Write\|Edit\|NotebookEdit\|Glob\|Grep\|Bash) | `guard-workspace-scope.py` | Block operations outside project directory | +| workspace-scope-guard | PreToolUse | `inject-workspace-cwd.py` | Inject working directory context | +| workspace-scope-guard | SessionStart | `inject-workspace-cwd.py` | Inject working directory at session start | +| workspace-scope-guard | UserPromptSubmit | `inject-workspace-cwd.py` | Inject working directory on prompt | +| workspace-scope-guard | SubagentStart | `inject-workspace-cwd.py` | Inject working directory for subagents | +| spec-workflow | Stop | `spec-reminder.py` | Remind about spec updates after code changes | +| skill-engine | UserPromptSubmit | `skill-suggester.py` | Suggest relevant skills based on prompt content | +| ticket-workflow | UserPromptSubmit | `ticket-linker.py` | Auto-fetch GitHub issues/PRs from `#123` references | +| notify-hook | Stop | (bell/OSC) | Desktop notification when Claude finishes | + +## Related + +- [Plugins](../plugins/) -- plugins that register hooks +- [Configuration](./configuration/) -- hook configuration and plugin toggles +- [Agent System](../plugins/agent-system/) -- agent-specific hooks for redirection and team quality gates +- [Architecture](../reference/architecture/) -- how hooks fit into the overall system pipeline diff --git a/docs/src/content/docs/customization/index.md b/docs/src/content/docs/customization/index.md new file mode 100644 index 0000000..f518f38 --- /dev/null +++ b/docs/src/content/docs/customization/index.md @@ -0,0 +1,128 @@ +--- +title: Customization +description: Overview of CodeForge customization options — configuration, system prompts, rules, and hooks. +sidebar: + order: 1 +--- + +CodeForge ships with opinionated defaults that work well out of the box, but every aspect of the environment is designed to be changed. Whether you want to swap the default model, add project-specific coding standards, or wire up custom automation scripts, you can do it without forking anything. + +## Customization Philosophy + +Three principles guide how CodeForge handles configuration: + +- **Sensible defaults with full override** -- The out-of-the-box setup reflects best practices for AI-assisted development. Nothing is locked down; you can change any behavior by editing the appropriate file. +- **Layered configuration** -- Settings compose from broad to specific. Default settings form the base, project settings override them, and environment variables override everything. You only need to specify what you want to change. +- **No magic** -- All configuration lives in readable files (JSON, Markdown, Python scripts). There is no hidden state, no binary configuration, and no behavior that you cannot trace to a specific file. + +## Configuration Layers + +Customization works through four layers, each targeting a different aspect of the environment: + +| Layer | What It Controls | Key Files | Documentation | +|-------|-----------------|-----------|---------------| +| [Configuration](./configuration/) | Feature flags, plugin toggles, runtime settings, container setup | `settings.json`, `devcontainer.json`, `file-manifest.json` | Settings and deployment | +| [System Prompts](./system-prompts/) | Claude Code behavior, coding standards, response style | `main-system-prompt.md`, `writing-system-prompt.md` | Behavioral guidance | +| [Rules](./rules/) | Hard constraints applied to all sessions | `.claude/rules/*.md` | Mandatory requirements | +| [Hooks](./hooks/) | Scripts that run at lifecycle points | `hooks.json` + Python scripts | Automation and validation | + +Each layer serves a distinct purpose. Configuration controls _what_ is active. System prompts shape _how_ Claude behaves. Rules define _what must or must not happen_. Hooks _automate actions_ at specific points in the workflow. + +## Quick Customizations + +Here are the most common changes you can make right away. + +### Change the Default Model + +Edit `settings.json` and change the `model` field: + +```json +{ + "model": "sonnet", + "env": { + "ANTHROPIC_MODEL": "claude-sonnet-4-5-20250929" + } +} +``` + +This takes effect on the next session. See [Configuration](./configuration/) for the full settings reference. + +### Toggle a Plugin + +Every plugin can be enabled or disabled in `settings.json` under `enabledPlugins`: + +```json +{ + "enabledPlugins": { + "auto-code-quality@devs-marketplace": false, + "agent-system@devs-marketplace": true + } +} +``` + +Set a plugin to `false` to disable it without removing it. + +### Add a Project Rule + +Create a Markdown file in `.claude/rules/` with your constraint: + +```markdown +# TypeScript Standards + +1. Always use strict mode +2. Never use `any` -- use `unknown` instead +3. All API responses must include error handling +``` + +The rule is loaded automatically on the next session. See [Rules](./rules/) for details. + +### Adjust Claude's Coding Style + +Edit the main system prompt at `.devcontainer/config/defaults/main-system-prompt.md`. Changes to this file are deployed to `.claude/` on container start. See [System Prompts](./system-prompts/) for guidance on effective prompt customization. + +### Add a Custom Hook + +Register a script in your plugin's `hooks/hooks.json` to automate quality checks, inject context, or block dangerous operations. See [Hooks](./hooks/) for the full hook API. + +### Disable a Feature + +Any local DevContainer feature can be turned off by setting `"version": "none"` in `devcontainer.json`: + +```json +{ + "features": { + "./features/shfmt": { "version": "none" }, + "./features/hadolint": { "version": "none" } + } +} +``` + +Rebuild the container after changing features. See [Configuration](./configuration/) for more on feature management. + +### Override an Environment Variable per Session + +You can override any setting for a single session by prefixing the command: + +```bash +ANTHROPIC_MODEL="claude-sonnet-4-5-20250929" cc +``` + +This is useful for testing a different model without changing your config files. See [Environment Variables](../reference/environment/) for all available variables. + +## How Configuration Flows + +When a CodeForge container starts, configuration is assembled in this order: + +1. **Container build** -- `devcontainer.json` installs features and runtimes +2. **Post-start setup** -- `setup.sh` runs scripts that deploy config files +3. **File manifest** -- `file-manifest.json` copies default settings, prompts, and rules to `.claude/` +4. **Plugin activation** -- Enabled plugins register their hooks +5. **Session start** -- Claude Code loads the system prompt, rules, and CLAUDE.md files + +At session time, the precedence order is: environment variables > project config > workspace config > defaults. + +## Related + +- [Plugins](../plugins/) -- the plugin system that many customizations target +- [Architecture](../reference/architecture/) -- how configuration layers interact at runtime +- [Environment Variables](../reference/environment/) -- complete reference for all env vars diff --git a/docs/src/content/docs/customization/rules.md b/docs/src/content/docs/customization/rules.md new file mode 100644 index 0000000..e9114ea --- /dev/null +++ b/docs/src/content/docs/customization/rules.md @@ -0,0 +1,175 @@ +--- +title: Rules +description: Global rules system for enforcing hard constraints across all Claude Code sessions. +sidebar: + order: 4 +--- + +Rules are Markdown files that define hard constraints applied to every Claude Code session. While system prompts _guide_ behavior, rules _enforce_ it. If a rule says "never do X," Claude treats that as a mandatory requirement, not a suggestion. + +## How Rules Work + +Rule files are Markdown documents placed in `.claude/rules/`. Claude Code loads every `.md` file in this directory at session start and treats their contents as mandatory instructions. The filename is descriptive but does not affect loading -- all files are loaded equally. + +Rules are deployed from `.devcontainer/config/defaults/rules/` to `.claude/rules/` via the file manifest on every container start. You can also add rules directly to `.claude/rules/` in your project. + +### Rule Precedence + +When rules exist at multiple levels, more specific rules take priority: + +1. **Project rules** (`.claude/rules/` in the project directory) -- highest precedence +2. **Workspace rules** (`.claude/rules/` at the workspace root) -- apply to all projects +3. **Built-in rules** (deployed by CodeForge) -- sensible defaults + +If a project rule conflicts with a workspace rule, the project rule wins. + +## Built-in Rules + +CodeForge ships three rules that are deployed by default: + +### Workspace Scoping (`workspace-scope.md`) + +Enforces that all file operations -- reads, writes, edits, searches, and bash commands -- stay within the current project directory. This prevents cross-project contamination in multi-project workspaces. + +```markdown +ALL file operations (reads, writes, edits, searches, globs, bash commands) +MUST target paths within the current project directory. No exceptions. +``` + +This rule works in concert with the [Workspace Scope Guard](../plugins/workspace-scope-guard/) plugin, which provides hook-level enforcement. + +### Spec Workflow (`spec-workflow.md`) + +Mandates specification-driven development. Every non-trivial feature requires a spec before implementation begins, and every implementation ends with an as-built spec update. + +Key requirements: +- Use `/spec-new` to create specs from the standard template +- Use `/spec-update` after implementation to close the loop +- Specs live in `.specs/` organized by domain folders +- Run `/spec-check` before starting new milestones + +### Session Search (`session-search.md`) + +Configures the `ccms` session history search tool. Mandates project-scoped searches to prevent cross-project information leakage, and requires CLI mode (no interactive TUI) for automation compatibility. + +Key requirements: +- Always pass `--project ` to scope results +- Always pass a query string (no bare `ccms` TUI mode) +- Use `--no-color` for clean output parsing +- Default to `-n 20` to limit result count + +## Creating Custom Rules + +### File Format + +Rules are plain Markdown files. Use headers, numbered lists, and bold text to make constraints clear and scannable: + +```markdown +# API Security Standards + +## Rules + +1. **All endpoints require authentication** -- no anonymous access + to any route except `/health` and `/docs`. +2. **Use parameterized queries exclusively** -- string interpolation + in SQL is forbidden, even for internal tools. +3. **Rate limit all public endpoints** -- minimum 100 req/min per IP + using the `slowapi` middleware. +4. **Validate all request bodies** -- use Pydantic models with + explicit field constraints (min/max length, regex patterns). +``` + +### Writing Effective Rules + +Rules work best when they follow these patterns: + +- **State the constraint clearly** -- "Never use `any` type" is better than "Prefer specific types" +- **Include brief rationale** -- "...because it bypasses type checking" helps Claude apply the rule to edge cases +- **Be specific enough to act on** -- "Use `pytest` with fixtures" rather than "Write good tests" +- **Keep each file focused** -- One concern per rule file makes it easy to toggle rules on and off + +:::caution[Rules Are Not Suggestions] +Claude treats rule file content as mandatory. If you write "consider using X," Claude will treat that as a firm instruction. Use definitive language: "always," "never," "must," "must not." +::: + +### Rule File Organization + +``` +.claude/ +└── rules/ + ├── spec-workflow.md # Built-in: specification workflow + ├── workspace-scope.md # Built-in: project isolation + ├── session-search.md # Built-in: ccms configuration + ├── coding-standards.md # Custom: your team's standards + ├── git-workflow.md # Custom: branching and commit rules + └── security.md # Custom: security requirements +``` + +### Adding a Rule to CodeForge Defaults + +To make a rule deploy automatically to all projects: + +1. Create the rule file in `.devcontainer/config/defaults/rules/` +2. Add an entry to `.devcontainer/config/file-manifest.json`: + +```json +{ + "src": "defaults/rules/my-rule.md", + "dest": "${CLAUDE_CONFIG_DIR}/rules", + "enabled": true, + "overwrite": "if-changed" +} +``` + +3. Rebuild the container to deploy + +## Example: Complete Custom Rule + +Here is a complete rule file you might use for a Node.js project: + +```markdown +# Node.js Project Standards + +## Mandatory Rules + +1. **Use ESM imports exclusively** -- no `require()` calls. + The project uses `"type": "module"` in package.json. +2. **All async functions must handle errors** -- wrap await calls + in try/catch or use `.catch()`. Unhandled rejections crash the server. +3. **Database queries use the query builder** -- never write raw SQL + strings. Use Knex or Drizzle query builder methods. +4. **Environment variables accessed through config module** -- never + read `process.env` directly in business logic. Import from + `src/config.ts` which validates all required vars at startup. +5. **Tests use vitest** -- not jest, not mocha. Run with + `vitest run` for CI and `vitest` for watch mode. + +## Rationale + +These rules prevent the most common bugs in this codebase: +mixed module systems, silent async failures, SQL injection, +missing env vars in production, and test runner confusion. +``` + +This rule would be saved as `.claude/rules/nodejs-standards.md` and loaded automatically on session start. + +## Rules vs. System Prompts vs. CLAUDE.md + +These three mechanisms serve distinct purposes and have different strengths: + +| Mechanism | Purpose | Best For | Enforcement | +|-----------|---------|----------|-------------| +| **Rules** | Hard constraints that must be followed | Security policies, workflow requirements, tool usage mandates | Highest -- treated as mandatory | +| **System Prompts** | Behavioral guidelines and coding standards | Response style, coding patterns, communication preferences | Medium -- guides behavior | +| **CLAUDE.md** | Project context and architecture | Tech stack, file structure, domain concepts | Informational -- provides context | + +:::note[When to Use Which] +Use **rules** when violation would cause real harm (security, data loss, workflow breakage). Use the **system prompt** for coding style and response preferences. Use **CLAUDE.md** for project-specific context that Claude needs to understand your codebase. +::: + +## Related + +- [System Prompts](./system-prompts/) -- behavioral guidelines that rules can override +- [Configuration](./configuration/) -- settings that control rule deployment via file-manifest +- [Workspace Scope Guard](../plugins/workspace-scope-guard/) -- the plugin that enforces the scoping rule +- [Spec Workflow](../plugins/spec-workflow/) -- the plugin that implements the spec workflow rule diff --git a/docs/src/content/docs/customization/system-prompts.md b/docs/src/content/docs/customization/system-prompts.md new file mode 100644 index 0000000..9a238be --- /dev/null +++ b/docs/src/content/docs/customization/system-prompts.md @@ -0,0 +1,189 @@ +--- +title: System Prompts +description: Customize Claude Code behavior through main and writing system prompts. +sidebar: + order: 3 +--- + +System prompts define how Claude Code behaves during your sessions -- its coding style, response format, tool usage patterns, and decision-making priorities. CodeForge ships two system prompts: one for development work and one for writing tasks. + +## Main System Prompt + +The main system prompt is loaded for every `cc` or `claude` session. It is the single most influential file in shaping how Claude works with your code. + +**Location:** `.devcontainer/config/defaults/main-system-prompt.md` +**Deployed to:** `.claude/main-system-prompt.md` + +### What It Controls + +The main prompt is organized into tagged sections, each governing a specific aspect of behavior: + +| Section | Purpose | +|---------|---------| +| `` | Priority ordering when rules conflict (safety first, then user instructions, then coding standards) | +| `` | Response structure, formatting, brevity rules, and communication style | +| `` | Technical accuracy over agreement, evidence-based corrections | +| `` | Subagent delegation, task decomposition, team composition, parallelization | +| `` | Coding standards (SOLID, DRY, function size, error handling, security) | +| `` | Verify before assuming, read before writing, no silent deviations | +| `` | Test behavior not implementation, mock limits, coverage expectations | + +### Structure + +The prompt uses XML-like tags to organize sections. This structure lets you modify one aspect of behavior without affecting others: + +```markdown + +Structure: +- Begin with substantive content; no preamble +- Use headers and bullets for multi-part responses +- Front-load key information; details follow + +Brevity: +- Provide concise answers by default +- Do not restate the problem back to the user +- Do not pad responses with filler or narrative + +``` + +Each section is self-contained. You can edit, remove, or add sections independently. + +## Writing System Prompt + +The writing system prompt is activated when you launch Claude with the `ccw` command. It replaces the development-focused prompt with one tuned for creative fiction writing. + +**Location:** `.devcontainer/config/defaults/writing-system-prompt.md` +**Deployed to:** `.claude/writing-system-prompt.md` + +### Key Differences from Main Prompt + +- Focuses on prose craft — darkly humorous third-person limited fiction style +- Provides emotional architecture guidance (controlled emotion, not suppressed) +- Includes genre-specific touchstones (Joe Abercrombie, Mark Lawrence) +- Replaces code standards with prose-quality principles and POV discipline + +:::tip[Quick Switch] +Use `cc` for coding sessions and `ccw` for writing sessions. Both are shell aliases that point Claude Code at different system prompt files. +::: + +## Customizing Prompts + +### Editing the Main Prompt + +To change development behavior, edit `.devcontainer/config/defaults/main-system-prompt.md`. Your changes are deployed to `.claude/` on the next container start via the file manifest. + +For changes to take effect immediately (without restarting the container), edit the deployed copy at `.claude/main-system-prompt.md` directly. Be aware that this copy will be overwritten on the next container rebuild unless you change the overwrite mode in `file-manifest.json`. + +### What to Customize + +Common modifications include: + +- **Coding standards** -- Add your team's specific conventions (naming, architecture patterns, preferred libraries) +- **Response style** -- Adjust verbosity, explanation depth, or formatting preferences +- **Tool usage** -- Change how Claude uses git, runs tests, or structures file operations +- **Security requirements** -- Add domain-specific security constraints +- **Testing approach** -- Modify test frameworks, coverage expectations, or mock limits + +### Example: Adding a Custom Section + +```markdown + +Framework: FastAPI + SQLAlchemy +- All endpoints use dependency injection for database sessions +- Use Pydantic v2 model_validator for complex validation +- Alembic for all schema migrations -- never modify tables directly +- API responses follow the envelope pattern: { data, meta, errors } + +``` + +Add this section anywhere in the system prompt. Claude will incorporate these conventions into its work. + +## Prompt Design Best Practices + +### Be Specific and Actionable + +Vague instructions lead to inconsistent behavior. Compare: + +| Weak | Strong | +|------|--------| +| "Write good tests" | "Use `pytest` with fixtures; every test function tests one behavior" | +| "Handle errors properly" | "Wrap external API calls in try/except; log the original error; raise a domain-specific exception" | +| "Follow best practices" | "Functions under 30 lines; no more than 3 parameters; pure where possible" | + +### State Constraints as Requirements + +Claude treats statements of fact as stronger guidance than suggestions: + +```markdown +# Weaker +- You should probably use TypeScript strict mode + +# Stronger +- TypeScript strict mode is always enabled. Never use `any`. +``` + +### Keep the Prompt Focused + +The system prompt should contain _behavioral instructions_, not domain knowledge. Move reference material elsewhere: + +| Content Type | Where It Belongs | +|-------------|-----------------| +| Coding standards and response style | System prompt | +| Project architecture and conventions | CLAUDE.md | +| Mandatory constraints | [Rules](./rules/) | +| Framework-specific reference | [Skills](../plugins/skill-engine/) | + +### Include Examples for Non-Obvious Conventions + +When your convention is not a common industry pattern, include a concrete example: + +```markdown + +API errors use the structured error envelope: +- Wrap handler logic in try/except +- Return {"error": {"code": "NOT_FOUND", "message": "..."}, "data": null} +- Log the full traceback to the structured logger +- Never expose internal error details to the client + +``` + +### Avoid Conflicting Instructions + +Review your prompt for contradictions. If one section says "always use descriptive variable names" and another says "keep code concise," Claude may produce inconsistent results. When two guidelines tension, state which takes priority. + +## System Prompts vs. Rules vs. CLAUDE.md + +These three mechanisms work together but serve different purposes: + +| Mechanism | Loaded | Purpose | Example | +|-----------|--------|---------|---------| +| **System prompt** | Every session, via `--system-prompt-file` | Behavioral guidelines and coding standards | "Begin with substantive content; no preamble" | +| **Rules** | Every session, from `.claude/rules/` | Hard constraints that must be followed | "ALL file operations MUST target the current project directory" | +| **CLAUDE.md** | Every session, from project root | Project context and conventions | "This project uses FastAPI with SQLAlchemy" | + +Rules override the system prompt when they conflict. CLAUDE.md provides context but does not enforce behavior. + +## Deployment and File Manifest + +Both system prompts are listed in `file-manifest.json` and deployed to `.claude/` on every container start: + +```json +{ + "src": "defaults/main-system-prompt.md", + "dest": "${CLAUDE_CONFIG_DIR}", + "enabled": true, + "overwrite": "if-changed" +} +``` + +The `if-changed` mode means your deployed copy is only overwritten when the source file's SHA-256 hash changes. If you want to make persistent local edits to the deployed prompt, change the overwrite mode to `"never"` so your changes survive container rebuilds. + +:::note[Two Copies] +The source file at `.devcontainer/config/defaults/main-system-prompt.md` is the canonical version. The deployed copy at `.claude/main-system-prompt.md` is what Claude Code actually loads. Edits to the source are deployed on next container start. Edits to the deployed copy take effect immediately but may be overwritten. +::: + +## Related + +- [Rules](./rules/) -- hard constraints complementing system prompts +- [Configuration](./configuration/) -- settings that affect prompt deployment +- [Agent System](../plugins/agent-system/) -- agents have their own specialized prompts diff --git a/docs/src/content/docs/features/agents.md b/docs/src/content/docs/features/agents.md new file mode 100644 index 0000000..b15f0b8 --- /dev/null +++ b/docs/src/content/docs/features/agents.md @@ -0,0 +1,303 @@ +--- +title: Agents +description: Complete reference for all 17 CodeForge agents — capabilities, tool access, and use cases. +sidebar: + order: 2 +--- + +CodeForge provides 17 specialized agents, each configured with a focused system prompt, specific tool access, and domain expertise. Claude automatically delegates to the appropriate agent based on your request — ask about architecture and you get the architect; ask for a security review and you get the security auditor. + +## How Agents Work + +Each agent is defined as a Markdown file in the agent system plugin's `agents/` directory. The file contains a YAML frontmatter header specifying the agent's name, tools, model, permission mode, and associated skills, followed by a detailed system prompt that shapes the agent's behavior, expertise, and constraints. + +When Claude receives your request, the agent system evaluates which specialist best matches your intent and spawns that agent as a subagent. The specialist operates within its defined boundaries — a read-only agent cannot modify files, and a full-access agent in a worktree cannot touch your main branch. + +### Built-In Agents, Replaced and Upgraded + +Claude Code ships with six built-in agent types: Explore, Plan, general-purpose, Bash, claude-code-guide, and statusline-setup. These are functional but generic — they carry no domain skills, have no safety hooks, and run with default tool access. + +CodeForge **entirely replaces** all six built-in agents with enhanced custom specialists. This happens transparently through a `PreToolUse` hook that intercepts every agent spawn request and redirects it before execution. You never interact with a stock agent — every request is silently upgraded to a purpose-built specialist with frontloaded skills, calibrated model selection, and hook-based safety enforcement. + +| Built-In Agent | Replaced By | What Changes | +|----------------|-------------|--------------| +| `Explore` | **explorer** | Haiku model for speed, ast-grep patterns skill, read-only enforcement | +| `Plan` | **architect** | Opus model for deep reasoning, api-design skill, structured 4-phase workflow | +| `general-purpose` | **generalist** | Full skill stack, spec workflow integration, plan mode support | +| `Bash` | **bash-exec** | Git safety protocols, path quoting enforcement, command validation | +| `claude-code-guide` | **claude-guide** | Pre-loaded Claude SDK and headless mode skills, documentation-first approach | +| `statusline-setup` | **statusline-config** | Sonnet model, focused tool access for status line configuration | + +The redirect is fully transparent — you can use either the built-in name or the custom name interchangeably. Asking Claude to "explore the codebase" triggers the same enhanced explorer agent whether the system selects the `Explore` type or the `explorer` type. + +Beyond the six replacements, CodeForge adds **11 entirely new specialists** that have no built-in equivalent: architect, researcher, test-writer, refactorer, doc-writer, migrator, security-auditor, dependency-analyst, git-archaeologist, perf-profiler, debug-logs, and spec-writer. These are available only in CodeForge. + +:::tip[Why This Matters] +The redirect happens at the hook level, not the prompt level. This means the upgrade is enforced — not suggested. Even if Claude's internal routing tries to use a stock Explore agent, the hook intercepts the call and swaps in the enhanced explorer before any code executes. The result is a strictly better agent every time, with zero user effort. +::: + +### Key Properties + +Every agent definition includes: + +- **Tools** — which Claude Code tools the agent can use (Read, Write, Edit, Bash, Glob, Grep, WebSearch, etc.) +- **Model** — which Claude model powers the agent (opus, sonnet, or haiku) +- **Permission mode** — `plan` (read-only), `acceptEdits` (can write with approval), or `default` (full access) +- **Isolation** — some agents run in git worktrees so their changes are isolated from your working branch +- **Background** — some agents run asynchronously, returning results while you continue working +- **Skills** — domain knowledge packs automatically loaded for the agent +- **Memory** — whether the agent remembers context across sessions (project-scoped or user-scoped) + +## Agent Reference + +### architect + +Read-only Opus api-design + +A senior software architect that designs implementation plans, analyzes trade-offs, and identifies critical files for proposed changes. The architect follows a structured four-phase workflow: understand requirements, explore the codebase, analyze and design, then structure the plan. It produces detailed implementation plans with phased steps, risk assessments, and testing strategies — but never modifies any files. + +**When activated:** Architecture questions, design reviews, "plan the implementation," "how should we architect this," system structure analysis. + +:::tip[Try this] +"Plan the implementation for adding WebSocket support to our API. Consider the existing REST patterns and suggest a phased approach." +::: + +### bash-exec + +Full Sonnet + +A command execution specialist for terminal operations. Handles git operations, build commands, test execution, process management, and complex shell scripting. Follows strict git safety protocols — never force-pushes, never amends without explicit permission, always quotes paths with spaces. + +**When activated:** Shell scripting tasks, git operations, build automation, "run this command." + +:::tip[Try this] +"Run the test suite for the auth module and show me a summary of results." +::: + +### claude-guide + +Read-only Haiku claude-code-headless claude-agent-sdk + +Your go-to expert for questions about Claude Code itself, the Claude Agent SDK, and the Claude API. Provides documentation-based guidance with specific examples and configuration snippets. Proactively suggests related features you might find useful. + +**When activated:** Questions about Claude Code features, "how do I configure hooks," "how do I use the Agent SDK," "can Claude do X." + +:::tip[Try this] +"How do I set up MCP tools with the Claude Agent SDK? Show me a TypeScript example." +::: + +### debug-logs + +Read-only Sonnet debugging + +A log analysis specialist that finds and analyzes log files across Docker containers, application frameworks, and system services. Follows a priority-based discovery strategy — Docker container logs first, then application log files, then system logs. Establishes chronology across sources to identify root causes in error cascades. + +**When activated:** Debugging sessions, "check the container logs," "why did this crash," error investigation, log analysis. + +:::tip[Try this] +"Investigate why the API container keeps restarting. Check the Docker logs and look for OOM kills or crash loops." +::: + +### dependency-analyst + +Read-only Haiku dependency-management + +Analyzes project dependencies for outdated packages, security vulnerabilities, version conflicts, unused dependencies, and license compliance issues. Supports Node.js, Python, Rust, and Go ecosystems. Runs in the background so you get results without waiting. + +**When activated:** "Check for outdated dependencies," "audit dependencies," "npm audit," "pip audit," dependency health checks. + +:::tip[Try this] +"Audit the project dependencies for security vulnerabilities and outdated packages." +::: + +### doc-writer + +Full (worktree) Opus documentation-patterns + +A technical writing specialist that creates and maintains README files, API documentation, inline comments (docstrings, JSDoc), and architectural guides. Reads and understands your code first, then produces documentation that reflects actual verified behavior — never aspirational or assumed behavior. Works in a git worktree for safe isolation. + +**When activated:** "Write a README," "document this module," "add docstrings," API documentation requests. + +:::tip[Try this] +"Document the public API for the user service module. Include usage examples and parameter descriptions." +::: + +### explorer + +Read-only Haiku + +A fast codebase navigator for file discovery, pattern matching, and structural analysis. Supports three thoroughness levels — quick (minimal tool calls), medium (balanced search), and very thorough (comprehensive investigation). Uses ast-grep and tree-sitter for syntax-aware structural search alongside standard Glob and Grep. + +**When activated:** "Find all files matching," "where is X defined," "how is this project structured," codebase orientation. + +:::tip[Try this] +"Find all API endpoint definitions in this project — very thorough. Show me the routing patterns and any anomalies." +::: + +### generalist + +Full Sonnet + +The general-purpose development agent for tasks that don't fit a specialized role. Has access to all tools and can handle mixed workloads — small features, bug fixes, multi-file investigations, and miscellaneous development tasks. Used when no specialist clearly matches. + +**When activated:** General development tasks, mixed-scope requests, tasks spanning multiple domains. + +:::tip[Try this] +"Fix the pagination bug in the search results endpoint and update the tests to cover the edge case." +::: + +### git-archaeologist + +Read-only Haiku git-forensics + +A git history forensics specialist that traces code evolution, finds when bugs were introduced, identifies authorship patterns, and recovers lost work from the reflog. Uses advanced git commands — blame with rename tracking (`-C -C -C`), pickaxe search (`-S`), and regex grep (`-G`). Never modifies git history or the working tree. + +**When activated:** "When was this changed," "who wrote this code," "find when this bug was introduced," git blame, git history questions. + +:::tip[Try this] +"Trace the history of the authentication middleware. When was it introduced, who has modified it, and what were the major changes?" +::: + +### migrator + +Full (worktree) Opus migration-patterns + +Plans and executes framework upgrades, language version bumps, API changes, and dependency migrations. Works methodically — creating a migration plan, transforming code in controlled steps, and verifying functionality after each change. Uses web research to consult official migration guides. Works in a git worktree so your main branch stays clean. + +**When activated:** "Migrate from X to Y," "upgrade to version N," "update the framework," "modernize the codebase." + +:::tip[Try this] +"Migrate our Pydantic v1 models to Pydantic v2 syntax. Plan the migration first, then execute it step by step." +::: + +### perf-profiler + +Read-only Sonnet performance-profiling + +A performance engineer that measures application performance, identifies bottlenecks, and recommends targeted optimizations backed by profiling data. Follows a rigorous measure-first approach — collects data before making claims, and every recommendation references specific measurements. Runs in the background. Never modifies code directly. + +**When activated:** "Profile this," "why is this slow," "find the bottleneck," "benchmark this function," performance questions. + +:::tip[Try this] +"Profile the database query in the search endpoint. Measure response times and identify the bottleneck." +::: + +### refactorer + +Full (worktree) Opus refactoring-patterns + +A disciplined refactoring specialist that performs behavior-preserving code transformations. Identifies code smells (god classes, deep nesting, duplication, long parameter lists), applies established refactoring patterns (extract function, replace conditional with polymorphism, introduce parameter object), and rigorously verifies that tests pass after every single edit via a PostToolUse hook. Works in a git worktree. + +**When activated:** "Refactor this," "clean up this code," "reduce complexity," "extract this function," "remove duplication." + +:::tip[Try this] +"Refactor the OrderProcessor class — it's a god class with 400 lines. Split it into focused components while keeping all tests green." +::: + +### researcher + +Read-only Sonnet documentation-patterns + +A technical research analyst that investigates codebases, searches documentation, and gathers web-based evidence to answer technical questions. Follows a disciplined codebase-first, web-second approach — local evidence is more reliable than generic documentation. Evaluates source recency, authority, and specificity. Produces structured reports with citations. + +**When activated:** "How does X work," "research this topic," "compare X vs Y," technology evaluation, technical deep-dives. + +:::tip[Try this] +"Research how our project handles authentication. Trace the full flow from request to authorization decision, then compare it against OWASP best practices." +::: + +### security-auditor + +Read-only Sonnet security-checklist + +A senior application security engineer that audits codebases for vulnerabilities using a structured four-phase methodology: reconnaissance (map the attack surface), OWASP Top 10 scan (check every category systematically), secrets scan (find hardcoded credentials), and configuration review (Docker, environment variables). Rates findings from CRITICAL to INFO with specific remediation guidance. Runs in the background. Never exposes actual secret values in output. + +**When activated:** "Audit this for security," "check for vulnerabilities," "scan for secrets," "OWASP review," security assessments. + +:::tip[Try this] +"Run a full security audit on the project. Check for OWASP Top 10 vulnerabilities, hardcoded secrets, and dependency CVEs." +::: + +### spec-writer + +Read-only Opus specification-writing + +A requirements engineer that creates structured technical specifications using the EARS (Easy Approach to Requirements Syntax) format for requirements and Given/When/Then patterns for acceptance criteria. Grounds every specification in the actual codebase state — reads existing code, tests, and interfaces before writing requirements. + +**When activated:** "Write a spec for," "define requirements," "create acceptance criteria," specification authoring. + +:::tip[Try this] +"Write a spec for the new notification preferences feature. Ground it in our existing user model and settings patterns." +::: + +### statusline-config + +Full Sonnet + +A specialist for configuring the Claude Code terminal statusline. Converts shell PS1 prompts to statusline commands, builds custom status displays, and integrates project-specific information into the status bar. Only modifies Claude Code settings files. + +**When activated:** "Set up my status line," "customize the status bar," "show git branch in status line." + +:::tip[Try this] +"Convert my current PS1 prompt to a Claude Code statusline. Include git branch, Python version, and working directory." +::: + +### test-writer + +Full (worktree) Opus testing + +A senior test engineer that analyzes existing code and writes comprehensive test suites. Detects test frameworks (pytest, Vitest, Jest, Go testing, Rust tests), follows project conventions exactly, and verifies all written tests pass before completing. A Stop hook automatically checks that no tests are failing when the agent finishes. Works in a git worktree. Never modifies source code — if a bug is found, it reports the bug rather than fixing it. + +**When activated:** "Write tests for," "add tests," "increase test coverage," "create unit tests," test writing requests. + +:::tip[Try this] +"Write comprehensive tests for the payment processing module. Cover happy paths, edge cases, and error scenarios. Follow our existing pytest conventions." +::: + +## Agent Capabilities Matrix + +| Agent | Access | Model | Isolation | Background | Key Skills | +|-------|--------|-------|-----------|------------|------------| +| architect | Read-only | Opus | -- | -- | api-design | +| bash-exec | Full | Sonnet | -- | -- | -- | +| claude-guide | Read-only | Haiku | -- | -- | claude-code-headless, claude-agent-sdk | +| debug-logs | Read-only | Sonnet | -- | -- | debugging | +| dependency-analyst | Read-only | Haiku | -- | Yes | dependency-management | +| doc-writer | Full | Opus | Worktree | -- | documentation-patterns | +| explorer | Read-only | Haiku | -- | -- | ast-grep-patterns | +| generalist | Full | Inherited | -- | -- | spec workflow | +| git-archaeologist | Read-only | Haiku | -- | -- | git-forensics | +| migrator | Full | Opus | Worktree | -- | migration-patterns | +| perf-profiler | Read-only | Sonnet | -- | Yes | performance-profiling | +| refactorer | Full | Opus | Worktree | -- | refactoring-patterns | +| researcher | Read-only | Sonnet | -- | -- | documentation-patterns | +| security-auditor | Read-only | Sonnet | -- | Yes | security-checklist | +| spec-writer | Read-only | Opus | -- | -- | specification-writing | +| statusline-config | Full | Sonnet | -- | -- | -- | +| test-writer | Full | Opus | Worktree | -- | testing | + +## Access Levels at a Glance + +| Access Level | Agents | +|-------------|--------| +| **Read-only** | architect, claude-guide, debug-logs, dependency-analyst, explorer, git-archaeologist, perf-profiler, researcher, security-auditor, spec-writer | +| **Full** | bash-exec, doc-writer, generalist, migrator, refactorer, statusline-config, test-writer | + +:::note[About Model Selection] +Agents use different Claude models based on task complexity. Opus handles the most demanding tasks (architecture, refactoring, test writing, migration). Sonnet covers analytical tasks that need strong reasoning (security audits, research, debugging). Haiku powers fast, focused tasks (exploration, dependency analysis, git history). The generalist inherits whichever model the main session is using. +::: + +## Safety Mechanisms + +Several agents include built-in safety hooks: + +- **Read-only bash guard** — The architect, explorer, security auditor, dependency analyst, and git-archaeologist all have a PreToolUse hook that blocks any Bash command that could modify files or state. +- **Git-readonly guard** — The git-archaeologist has a specialized guard that only permits read-only git subcommands (log, blame, show, diff, reflog, etc.). +- **Post-edit test verification** — The refactorer runs tests automatically after every single Edit operation. If tests fail, the change is immediately reverted. +- **Stop verification** — The test-writer has a Stop hook that verifies all written tests pass before the agent completes. + +## Related + +- [Agent System Plugin](../plugins/agent-system/) — how the agent system works +- [Skills](./skills/) — knowledge packs agents can leverage +- [Hooks](../customization/hooks/) — hook scripts that support agents diff --git a/docs/src/content/docs/features/code-intelligence.md b/docs/src/content/docs/features/code-intelligence.md new file mode 100644 index 0000000..65bbd23 --- /dev/null +++ b/docs/src/content/docs/features/code-intelligence.md @@ -0,0 +1,207 @@ +--- +title: Code Intelligence +description: AST-based code analysis with ast-grep and tree-sitter, plus Language Server Protocol integration for rich code navigation. +sidebar: + order: 5 +--- + +CodeForge provides three layers of code intelligence that work together: structural pattern matching with ast-grep, syntax tree parsing with tree-sitter, and semantic analysis with LSP servers. Each layer serves a different purpose, and knowing when to reach for each one makes you (and Claude) dramatically more effective at understanding and navigating code. + +## When to Use What + +Before diving into each tool, here is the decision framework: + +| You need to... | Use | Why | +|----------------|-----|-----| +| Find a text string or identifier | `grep` / Grep tool | Fastest for literal text | +| Find a code pattern with variable parts | **ast-grep** (`sg`) | Understands syntax, ignores comments and strings | +| Parse a file's structure or extract all symbols | **tree-sitter** | Deepest structural insight per file | +| Get type info, jump to definition, or find all references | **LSP** | Semantic analysis with full type understanding | + +:::tip[Start simple, escalate when needed] +Default to Grep for simple searches. Escalate to ast-grep when your pattern has variable sub-expressions or when you need to distinguish real code from strings and comments. Use LSP when you need semantic understanding — type information, definition lookups, or call hierarchies. +::: + +## ast-grep + +ast-grep (`sg` command, also available as `ast-grep`) enables structural code search using Abstract Syntax Tree patterns. Unlike text-based search, ast-grep understands code structure — it matches patterns regardless of formatting, whitespace, or naming, and it never matches inside comments or string literals. + +### Basic Usage + +```bash +# Find all console.log calls, regardless of arguments +sg --pattern 'console.log($$$)' --lang js + +# Find Python functions decorated with @app.route +sg --pattern '@app.route($PATH)' --lang python + +# Find all async function definitions in a directory +sg --pattern 'async def $NAME($$$PARAMS)' --lang python src/api/ + +# Find fetch calls with any options +sg --pattern 'fetch($URL, $$$OPTS)' --lang typescript +``` + +### Metavariables + +Metavariables are the key to writing effective ast-grep patterns: + +| Syntax | Matches | Example | +|--------|---------|---------| +| `$NAME` | Any single AST node | `$FUNC($ARG)` matches `foo(bar)` | +| `$$$ARGS` | Zero or more nodes (variadic) | `console.log($$$ARGS)` matches `console.log()`, `console.log(a)`, `console.log(a, b, c)` | + +The `$` prefix with a name creates a named capture. The `$$$` prefix creates a variadic capture that matches any number of nodes, including zero. + +### Structural Replace + +ast-grep can also transform code, not just search for it: + +```bash +# Convert var to const +sg --pattern 'var $NAME = $VALUE' --rewrite 'const $NAME = $VALUE' --lang js + +# Convert require to import +sg --pattern 'const $NAME = require($PATH)' --rewrite 'import $NAME from $PATH' --lang js + +# Add error handling to fetch calls +sg --pattern 'await fetch($URL)' --rewrite 'await fetch($URL).catch(handleError)' --lang ts +``` + +:::caution[Preview before rewriting] +Always run a search first (`sg --pattern ...`) to see what will be matched before using `--rewrite`. Structural replace modifies files in place. +::: + +### Real-World Patterns + +Here are patterns that solve common code search problems: + +```bash +# Find all class definitions with their names +sg --pattern 'class $NAME { $$$BODY }' --lang python + +# Find specific decorator usage +sg --pattern '@pytest.mark.parametrize($$$ARGS)' --lang python + +# Find import statements for a specific module +sg --pattern 'from $MOD import $$$NAMES' --lang python + +# Find all try/except blocks (Python) +sg --pattern 'try: $$$BODY except $$$HANDLERS' --lang python + +# Find React useState hooks +sg --pattern 'const [$STATE, $SETTER] = useState($$$INIT)' --lang tsx + +# Find all Express route handlers +sg --pattern 'app.$METHOD($PATH, $$$HANDLERS)' --lang js +``` + +### Why Not Just Use Grep? + +Consider searching for all calls to `fetch()`: + +- **Grep** `fetch(` matches: function calls, comments mentioning fetch, strings containing "fetch(", variable names like `fetchData(`, and import statements. +- **ast-grep** `fetch($$$ARGS)` matches: only actual `fetch()` function calls in the AST, nothing else. + +For simple identifier lookups, Grep is faster and sufficient. For pattern matching where structure matters, ast-grep eliminates false positives. + +## tree-sitter + +tree-sitter provides incremental parsing and concrete syntax tree operations. It parses source files into syntax trees that you can query, inspect, and traverse. CodeForge installs tree-sitter with grammars for JavaScript, TypeScript, and Python pre-loaded. + +### Basic Usage + +```bash +# Parse a file and output its syntax tree +tree-sitter parse src/main.py + +# Extract all tagged definitions (functions, classes, methods) from a file +tree-sitter tags src/main.py + +# Query the syntax tree with S-expression patterns +tree-sitter query '(function_definition name: (identifier) @name)' src/main.py +``` + +### When to Use tree-sitter + +tree-sitter is most useful when you need to: + +- **Understand file structure** — `tree-sitter tags` extracts all definitions (functions, classes, methods) from a file, giving you a quick symbol inventory. +- **Inspect nesting and complexity** — `tree-sitter parse` shows the full syntax tree, revealing nesting depth and structural complexity. +- **Write precise queries** — tree-sitter's S-expression query language lets you match specific syntactic constructs with field-level precision. + +### tree-sitter vs ast-grep + +Both tools work with syntax trees, but they serve different purposes: + +| Feature | tree-sitter | ast-grep | +|---------|-------------|----------| +| **Scope** | Single file, deep analysis | Multi-file search | +| **Query syntax** | S-expressions (precise, verbose) | Code patterns (intuitive, concise) | +| **Best for** | Symbol extraction, parse tree inspection | Finding patterns across a codebase | +| **Output** | Syntax tree structure | Matching code locations | + +In practice, Claude and the specialized agents use ast-grep for cross-file pattern searches and tree-sitter for per-file structural analysis. The [ast-grep-patterns skill](./skills/) provides comprehensive guidance for both tools. + +## Language Server Protocol (LSP) + +LSP servers provide semantic code intelligence — they understand types, scopes, definitions, and references at a level that syntax analysis alone cannot reach. CodeForge configures LSP servers for your installed language runtimes, giving Claude access to the same "go to definition" and "find references" operations your IDE provides. + +### Installed LSP Servers + +| Language | Server | Version | +|----------|--------|---------| +| **Python** | Pyright | 1.1.408 | +| **TypeScript/JavaScript** | typescript-language-server | 5.1.3 (with TypeScript 5.9.3) | +| **Go** | gopls | latest | + +### Available Operations + +| Operation | What it does | When to use it | +|-----------|-------------|----------------| +| `goToDefinition` | Jump to where a symbol is defined | "Where is this function defined?" | +| `findReferences` | Find all usages of a symbol | "Where is this class used?" | +| `hover` | Get type info and documentation | "What type does this return?" | +| `documentSymbol` | List all symbols in a file | "What functions are in this file?" | +| `workspaceSymbol` | Search symbols across the project | "Find all classes named Controller" | +| `goToImplementation` | Find interface implementations | "What implements this interface?" | +| `incomingCalls` | Find callers of a function | "What calls this function?" | +| `outgoingCalls` | Find callees from a function | "What does this function call?" | + +### How LSP Differs from ast-grep + +LSP understands **semantics** — types, scopes, and definitions. ast-grep understands **syntax** — code patterns and structure. + +For example, if you search for `UserService` with ast-grep, you find every syntactic occurrence of that identifier. With LSP `findReferences`, you find only the places where that specific `UserService` class (the one defined in `services/user.py:15`) is actually used — excluding same-named classes in other modules, string mentions, and comments. + +| Need | ast-grep | LSP | +|------|----------|-----| +| Find a code pattern | Excellent — designed for this | Not applicable | +| Find all references to a specific symbol | Finds text matches (may include false positives) | Finds semantic references (precise) | +| Get type information | Cannot | Full type inference | +| Navigate definition chains | Cannot | Go-to-definition across files | +| Work without a running server | Works immediately | Requires server startup | + +## How They Work Together + +The three tools form a progression from fast-and-broad to slow-and-precise: + +``` +Grep (text) → ast-grep (syntax) → LSP (semantics) + Fastest Fast Precise + Broadest Focused Narrowest +``` + +A typical investigation might use all three: + +1. **Grep** to find files mentioning `authenticate` — casts a wide net quickly. +2. **ast-grep** to find all function calls to `authenticate(...)` — filters out comments, strings, and variable names. +3. **LSP** `findReferences` on the specific `authenticate` function in `auth/middleware.py` — finds only the call sites for that exact function, not other functions with the same name. + +Claude and the specialized agents (especially the explorer and architect) use this progression automatically, starting with the fastest tool and escalating when precision matters. + +## Related + +- [CodeForge LSP Plugin](../plugins/codeforge-lsp/) — LSP server configuration +- [Tools Reference](./tools/) — CLI commands for these tools +- [ast-grep Patterns Skill](./skills/) — pattern-writing guidance diff --git a/docs/src/content/docs/features/index.md b/docs/src/content/docs/features/index.md new file mode 100644 index 0000000..eab9c4e --- /dev/null +++ b/docs/src/content/docs/features/index.md @@ -0,0 +1,114 @@ +--- +title: Features +description: Overview of CodeForge features — agents, skills, CLI tools, and code intelligence capabilities. +sidebar: + order: 1 +--- + +CodeForge turns your DevContainer into a fully equipped AI development environment. Every feature is pre-configured and ready to use the moment your container starts — no setup scripts to run, no extensions to install, no configuration files to write. + +This section is your reference guide to everything CodeForge provides. Whether you need a specialized AI agent to audit your security posture, a skill pack to guide your FastAPI development, or a CLI tool to search your session history, you will find it documented here. + +## What You Get + +Out of the box, CodeForge gives you: + +- **17 specialized AI agents** with focused expertise and safety-calibrated tool access +- **21 domain knowledge packs** (skills) for frameworks, patterns, and workflows +- **21 CLI tools** for session management, code quality, and development +- **3 layers of code intelligence** — AST-based search, syntax parsing, and LSP semantic analysis +- **12 plugins** that wire everything together with hooks, guards, and automation + +All of these features work together. An agent can load skills for domain expertise, use CLI tools for code quality checks, and leverage code intelligence for precise navigation — all orchestrated automatically. + +## AI Agents + +CodeForge includes **17 specialized AI agents**, each with focused expertise, calibrated tool access, and a detailed system prompt that shapes its behavior. When you ask Claude a question, the agent system automatically delegates to the right specialist — an architect for design questions, a security auditor for vulnerability reviews, a test writer for coverage gaps. + +Agents fall into two categories: + +- **Read-only agents** (10 total) — can search, read, and analyze your codebase but never modify it. These include the architect, explorer, security auditor, researcher, dependency analyst, and spec-writer. +- **Full-access agents** (7 total) — can read, write, and execute commands. These include the test writer, refactorer, migrator, doc writer, and generalist. + +A key distinction: CodeForge doesn't just add new agents — it **replaces Claude Code's six built-in agent types entirely**. A `PreToolUse` hook intercepts every agent spawn and transparently redirects stock agents (Explore, Plan, general-purpose, Bash, claude-code-guide, statusline-setup) to enhanced custom specialists with frontloaded skills, calibrated models, and safety hooks. You never interact with a generic agent — every request is silently upgraded. The remaining 11 agents (test-writer, refactorer, security-auditor, and others) are entirely new specialists with no built-in equivalent. + +Key safety features set CodeForge agents apart: + +- **Worktree isolation** — agents like the refactorer, test-writer, migrator, and doc-writer work in git worktrees, so their changes never touch your working branch until you merge them. +- **Background execution** — agents like the security auditor, dependency analyst, and perf profiler run asynchronously, returning results while you continue working. +- **Hook enforcement** — read-only agents have bash guards that block any command that could modify files. The refactorer runs tests after every single edit. The test writer verifies all tests pass before completing. +- **Built-in replacement** — all six of Claude Code's stock agents are intercepted at the hook level and replaced with strictly better specialists. This is enforced, not suggested. + +[View all 17 agents →](./agents/) + +## Skills + +**21 domain-specific knowledge packs** give Claude deep expertise in frameworks, patterns, and workflows. When you start discussing FastAPI routes or Svelte 5 runes, the skill engine detects the context and auto-suggests the relevant skill. Once loaded, the skill injects structured knowledge — best practices, code patterns, API references, and common pitfalls — directly into Claude's context for the current task. + +Each skill is built around a "mental model" — a concise explanation of how a technology works, followed by concrete patterns, code examples, and guidance. This is not generic documentation; skills encode the kind of working knowledge a senior specialist carries. + +Skills cover three categories: + +| Category | Examples | What They Provide | +|----------|----------|-------------------| +| **Frameworks** | FastAPI, Svelte 5, Docker, Pydantic AI, SQLite | Framework-specific patterns, API usage, and testing guidance | +| **Practices** | Testing, Debugging, Security, Refactoring, API Design | Methodology, checklists, and established patterns | +| **Claude & CodeForge** | Agent SDK, Headless Mode, Skill Building, Spec Writing | Guidance for building on and extending CodeForge itself | + +[View all 21 skills →](./skills/) + +## CLI Tools + +CodeForge pre-installs **21 tools and utilities** covering session management, code quality, language runtimes, and development infrastructure. Every tool is available on your `PATH` from the first terminal session — run `cc-tools` to see everything installed and its version. + +Highlights include: + +- **`cc`** — Launch Claude Code with full CodeForge configuration (plugins, system prompt, agents) +- **`ccms`** — Search your Claude Code session history with boolean queries, role filtering, and time scoping +- **`ccusage`** / **`ccburn`** — Track your Claude API token usage and burn rate +- **`ruff`**, **`biome`**, **`shellcheck`** — Code quality tools for Python, JS/TS, and Shell +- **`sg`** (ast-grep), **`tree-sitter`** — Structural code search and syntax tree operations + +[View CLI tools reference →](./tools/) + +## Code Intelligence + +Understanding code requires more than text search. CodeForge provides three complementary layers of code intelligence that give Claude (and you) progressively deeper understanding of your codebase: + +| Layer | Tool | Strength | +|-------|------|----------| +| **Pattern matching** | ast-grep (`sg`) | Find code patterns across files using AST-aware search | +| **Syntax parsing** | tree-sitter | Parse files into syntax trees, extract symbols and structure | +| **Semantic analysis** | LSP servers | Type information, go-to-definition, find-references, and more | + +CodeForge installs LSP servers for Python (Pyright), TypeScript/JavaScript, and Go (gopls), giving Claude access to the same semantic operations your IDE uses — but available programmatically from the terminal. + +[View code intelligence features →](./code-intelligence/) + +## Feature Summary + +| Category | Count | Highlights | +|----------|-------|------------| +| [Agents](./agents/) | 17 | Architect, Explorer, Security Auditor, Test Writer, Refactorer, and 12 more | +| [Skills](./skills/) | 21 | FastAPI, Svelte 5, Docker, Testing, Debugging, Security, and 15 more | +| [CLI Tools](./tools/) | 21 | Session search, token tracking, code quality, formatters, and runtimes | +| [Code Intelligence](./code-intelligence/) | 3 | ast-grep, tree-sitter, LSP servers for Python/TS/Go | + +## How Features Are Delivered + +All CodeForge features are delivered through the [plugin system](../plugins/). Agents come from the [Agent System Plugin](../plugins/agent-system/), skills from the [Skill Engine Plugin](../plugins/skill-engine/), and code quality tools are automated by the [Auto Code Quality Plugin](../plugins/auto-code-quality/). CLI tools are installed as [DevContainer features](../customization/devcontainer/) during container build. + +This architecture means you can enable, disable, or customize any feature without modifying the others: + +- **Add an agent** — drop a Markdown file in the agents directory with the right frontmatter +- **Create a skill** — write a `SKILL.md` file following the skill template +- **Install a tool** — add a DevContainer feature to your `devcontainer.json` +- **Disable anything** — set `"version": "none"` for features, or remove plugins from the enabled list + +Everything is modular and extensible. See [Customization](../customization/) for the full guide. + +## Related + +- [Plugins](../plugins/) — the plugin system that delivers these features +- [Customization](../customization/) — configure and extend features +- [Commands Reference](../reference/commands/) — all CLI commands in one table diff --git a/docs/src/content/docs/features/skills.md b/docs/src/content/docs/features/skills.md new file mode 100644 index 0000000..9b5b040 --- /dev/null +++ b/docs/src/content/docs/features/skills.md @@ -0,0 +1,230 @@ +--- +title: Skills +description: Complete reference for all 21 CodeForge skills — domain knowledge packs for frameworks, patterns, and workflows. +sidebar: + order: 3 +--- + +Skills are domain-specific knowledge packs that give Claude deep expertise in specific technologies, patterns, and workflows. Instead of relying on general training data, a loaded skill injects structured, curated knowledge — best practices, code patterns, API references, mental models, and common pitfalls — directly into Claude's context for your current task. + +## How Skills Work + +Each skill is a `SKILL.md` file containing structured knowledge organized around a central mental model. When loaded, this knowledge becomes part of Claude's working context, giving it the equivalent of having a senior specialist's reference guide open while working on your code. + +### Auto-Suggestion + +The skill engine monitors your conversation and automatically suggests relevant skills based on context. If you start discussing FastAPI routes, the `fastapi` skill is suggested. If you mention refactoring a class, `refactoring-patterns` appears. You can accept the suggestion to load the skill, or ignore it and continue working. + +### Manual Invocation + +You can also load skills explicitly when you know you need specific expertise. Skills declared in an agent's configuration are loaded automatically when that agent is spawned. + +:::tip[When skills shine] +Skills are most valuable when you are working in a specific domain and need Claude to follow established patterns rather than improvise. Loading the `testing` skill before writing tests ensures Claude follows your project's pytest conventions. Loading `security-checklist` before a review ensures no OWASP category is missed. +::: + +## Framework Skills + +These skills provide deep knowledge of specific frameworks and technologies — API patterns, configuration idioms, testing approaches, and common pitfalls. + +### fastapi + +Modern FastAPI development including REST APIs, Pydantic v2 models, SSE streaming, dependency injection, and ASGI middleware patterns. Covers the type-driven contract model where function signatures define the entire API contract — path parameters, query parameters, request bodies, and response models all declared through type annotations. + +**Key topics:** Route definitions, dependency injection graphs, Pydantic v2 validation, SSE streaming with sse-starlette, background tasks, middleware ordering, OpenAPI schema customization. + +**Auto-suggested when:** You mention FastAPI, Pydantic models, APIRouter, SSE streaming, or ASGI middleware. + +### svelte5 + +Svelte 5 development with the new runes reactivity system. Covers the shift from Svelte 4's compiler-magic reactivity to Svelte 5's explicit runes — `$state`, `$derived`, `$effect`, `$props`, and `$bindable`. Includes component patterns, event handling, and migration guidance from Svelte 4. + +**Key topics:** Rune-based reactivity, component composition, snippet blocks, event handling with `onclick` instead of `on:click`, SvelteKit integration, transition and animation patterns. + +**Auto-suggested when:** You mention Svelte, runes, `$state`, `$derived`, SvelteKit, or component rendering. + +### docker + +Docker and Docker Compose patterns for containerized development and deployment. Covers Dockerfile best practices (multi-stage builds, layer caching, security hardening), Compose service orchestration, networking, volumes, and health checks. + +**Key topics:** Multi-stage builds, layer optimization, .dockerignore, Compose service dependencies, named volumes, bridge networks, health check configuration, production hardening. + +**Auto-suggested when:** You mention Docker, Dockerfile, Compose, container builds, or image optimization. + +### docker-py + +Python Docker SDK for managing containers, images, networks, and volumes programmatically. Covers the `docker` Python package API for automation scripts, CI/CD tooling, and container orchestration from Python code. + +**Key topics:** Container lifecycle management, image operations, network configuration, volume management, streaming logs, exec commands, Docker API authentication. + +**Auto-suggested when:** You mention the Docker Python SDK, `docker.from_env()`, or programmatic container management. + +### pydantic-ai + +Pydantic AI agent framework for building structured AI agents in Python. Covers agent definition, tool registration, structured outputs with Pydantic models, streaming, dependency injection, and testing patterns. + +**Key topics:** Agent definition with system prompts, tool decorators, structured result types, streaming responses, RunContext dependencies, testing with `TestModel`, multi-model support. + +**Auto-suggested when:** You mention Pydantic AI, AI agents in Python, structured AI outputs, or tool-using agents. + +### sqlite + +SQLite database patterns for embedded and application databases. Covers schema design, query optimization, WAL mode for concurrent access, connection management, migration strategies, and common pitfalls that trip up developers coming from client-server databases. + +**Key topics:** WAL mode configuration, `PRAGMA` tuning, connection pooling, schema migrations, full-text search (FTS5), JSON functions, transaction isolation, backup strategies. + +**Auto-suggested when:** You mention SQLite, database queries, schema migrations, or WAL mode. + +## Practice Skills + +These skills teach methodologies, checklists, and established patterns that apply across frameworks and languages. + +### testing + +Test writing patterns for FastAPI endpoints and Svelte 5 components using pytest and Vitest. Emphasizes testing behavior at public interfaces — HTTP contracts for backends, rendered output for frontends. Covers the arrange-act-assert pattern with specific isolation mechanisms for each stack. + +**Key topics:** pytest fixtures and parametrize, httpx AsyncClient for FastAPI, `app.dependency_overrides`, Vitest with @testing-library/svelte, MSW for network mocking, test organization strategies. + +**Auto-suggested when:** You mention writing tests, pytest, Vitest, test coverage, or mocking dependencies. + +### debugging + +Systematic log analysis and error diagnosis across Docker, systemd, and application environments. Treats logs as forensic evidence and follows a scientific method: observe symptoms, form hypotheses, gather evidence, test hypotheses, converge on root cause. + +**Key topics:** Docker exit code interpretation, container log analysis, Python traceback reading, error cascade identification, chronology-based diagnosis, cross-source correlation, OOM detection. + +**Auto-suggested when:** You mention debugging, log analysis, "why did this crash," Docker logs, or error investigation. + +### refactoring-patterns + +Behavior-preserving code transformations with a smell-detect, transform, verify cycle. Covers the full catalog of code smells (god class, feature envy, data clumps, primitive obsession) and their corresponding mechanical transformations, with language-specific idioms for Python and TypeScript. + +**Key topics:** Extract function/class, inline function, replace conditional with polymorphism, introduce parameter object, guard clauses, consolidate duplicate logic, smell severity assessment. + +**Auto-suggested when:** You mention refactoring, code smells, extracting functions, reducing complexity, or cleaning up code. + +### security-checklist + +Defense-in-depth security review covering OWASP Top 10, secrets detection, and dependency CVE scanning. Built around the principle that every vulnerability exists at a boundary where untrusted data is treated as trusted. + +**Key topics:** Input boundary validation, SQL/command/template injection patterns, secret scanning regex, dependency auditing (pip-audit, npm audit, trivy), CORS configuration, JWT validation, password hashing algorithms. + +**Auto-suggested when:** You mention security, vulnerabilities, OWASP, secrets scanning, or dependency auditing. + +### api-design + +REST API design conventions covering the full lifecycle from URL structure to error responses. Provides consistent patterns for resource naming, HTTP method semantics, pagination, filtering, and versioning. + +**Key topics:** URL structure and naming, HTTP method/status code conventions, pagination strategies, filtering and sorting, error response format, API versioning, HATEOAS considerations. + +**Auto-suggested when:** You mention API design, REST endpoints, pagination, or API versioning. + +### documentation-patterns + +Documentation standards and templates for technical writing. Covers README structure, API documentation, inline comments, architectural decision records (ADRs), and documentation generation tooling. + +**Key topics:** README template sections, API documentation structure, docstring conventions, ADR format, when to document vs when code should be self-explanatory, documentation-as-code practices. + +**Auto-suggested when:** You mention writing documentation, README files, API docs, or docstrings. + +### performance-profiling + +Performance measurement and optimization methodology. Follows a rigorous measure-first approach — identify metrics, establish baselines, profile, then optimize based on data rather than intuition. + +**Key topics:** CPU profiling (cProfile, py-spy), memory analysis, I/O bottleneck identification, database query optimization (EXPLAIN ANALYZE), benchmarking techniques, complexity analysis. + +**Auto-suggested when:** You mention profiling, performance, bottlenecks, "why is this slow," or benchmarking. + +### dependency-management + +Dependency analysis and management across package ecosystems. Covers version resolution strategies, conflict detection, upgrade planning, vulnerability assessment, and lockfile management for npm, pip/uv, Cargo, and Go modules. + +**Key topics:** Semantic versioning, version pinning strategies, lockfile management, vulnerability scanning, license compliance, dependency graph analysis, upgrade path planning. + +**Auto-suggested when:** You mention dependency updates, version conflicts, package auditing, or lockfile issues. + +### migration-patterns + +Migration strategies for frameworks, databases, and architectures. Covers incremental migration techniques that keep the system deployable at every step, with rollback strategies for when things go wrong. + +**Key topics:** Strangler fig pattern, database migration tools (Alembic, Prisma, goose), schema evolution, data migration scripts, forward/backward compatibility, feature flags for gradual rollout. + +**Auto-suggested when:** You mention migration, upgrading frameworks, database schema changes, or version bumps. + +## Claude & CodeForge Skills + +These skills help you build on and extend the Claude ecosystem itself. + +### claude-agent-sdk + +Claude Agent SDK patterns in TypeScript for building programmatic AI agents. Covers the `query()` function, permission callbacks, MCP tool integration, subagent orchestration, and hooks — the same agent loop that powers Claude Code, available as a library. + +**Key topics:** `query()` async generator, `canUseTool` permission callback, `createSdkMcpServer` for custom tools, subagent definitions, message streaming, Bedrock/Vertex AI/Azure AI Foundry configuration. + +**Auto-suggested when:** You mention the Claude Agent SDK, building agents with Claude, `@anthropic-ai/claude-agent-sdk`, or programmatic Claude usage. + +### claude-code-headless + +Running Claude Code in headless and CI mode for automation. Covers non-interactive usage, piping prompts, parsing JSON output, CI/CD integration patterns, and automating repetitive development tasks. + +**Key topics:** `--print` flag for non-interactive mode, JSON output parsing, CI pipeline integration, automation scripts, session management for headless runs. + +**Auto-suggested when:** You mention running Claude in CI, headless mode, automation with Claude Code, or non-interactive usage. + +### skill-building + +Creating new skills for the CodeForge skill engine. Covers the `SKILL.md` format, content structure, mental model design, and best practices for writing skills that effectively transfer domain knowledge to Claude. + +**Key topics:** SKILL.md YAML frontmatter, mental model section design, pattern documentation, when-to-use triggers, skill versioning, testing skill effectiveness. + +**Auto-suggested when:** You mention creating skills, writing a SKILL.md, extending the skill engine, or customizing CodeForge knowledge. + +### git-forensics + +Git history analysis techniques for tracing code evolution and investigating changes. Covers advanced git commands for blame, bisect, reflog archaeology, and commit pattern analysis. + +**Key topics:** `git blame -C -C -C` for rename tracking, pickaxe search with `-S` and `-G`, reflog recovery, `git shortlog` for contribution analysis, merge-base identification, commit archaeology. + +**Auto-suggested when:** You mention git history, git blame, bisect, "when was this changed," or code archaeology. + +### specification-writing + +EARS format specification authoring for structured technical requirements. Covers the five requirement types (ubiquitous, event-driven, state-driven, optional, unwanted) and Given/When/Then acceptance criteria patterns. + +**Key topics:** EARS requirement syntax, Given/When/Then acceptance criteria, requirement traceability, spec organization in `.specs/` directories, approval workflow (draft to approved). + +**Auto-suggested when:** You mention writing specs, defining requirements, acceptance criteria, or EARS format. + +### ast-grep-patterns + +Syntax-aware code search using ast-grep (`sg`) and tree-sitter. Teaches when to use structural search over text search and how to write effective AST patterns with metavariables. + +**Key topics:** `$NAME` single-node metavariables, `$$$ARGS` variadic metavariables, language-specific patterns (Python, TypeScript, JavaScript, Rust), rule composition, combining ast-grep with tree-sitter for deep structural analysis. + +**Auto-suggested when:** You mention ast-grep, structural search, syntax-aware search, tree-sitter queries, or code pattern matching. + +### team + +Agent team orchestration for parallel workstreams. Guides the creation and coordination of specialist agent teams using `TeamCreate`, task assignment, and message passing. Teams add value when work can be parallelized across 3 or more independent streams. + +**Key topics:** Team creation, task decomposition, specialist selection, parallel vs sequential work assessment, message coordination, result integration, team lifecycle management. + +**Auto-suggested when:** You mention spawning a team, working in parallel, coordinating multiple agents, or splitting work across agents. + +## Skill Categories Summary + +| Category | Skills | Focus | +|----------|--------|-------| +| **Frameworks** | fastapi, svelte5, pydantic-ai, docker, docker-py, sqlite | Framework-specific patterns and APIs | +| **Practices** | testing, debugging, refactoring-patterns, security-checklist, api-design, documentation-patterns, performance-profiling, dependency-management, migration-patterns | Methodologies and established patterns | +| **Claude & CodeForge** | claude-code-headless, claude-agent-sdk, skill-building, git-forensics, specification-writing, ast-grep-patterns, team | Building on and extending the Claude ecosystem | + +:::note[Skills vs Agents] +Skills and agents serve different purposes. An **agent** is a specialized Claude instance with specific tools and constraints — it *does work*. A **skill** is a knowledge pack that *informs work* — it provides the patterns, best practices, and domain knowledge that make an agent (or the main Claude session) more effective. Many agents have associated skills that load automatically when the agent is spawned. +::: + +## Related + +- [Skill Engine Plugin](../plugins/skill-engine/) — how the skill engine works +- [Agents](./agents/) — agents that leverage skills +- [Spec Workflow](../plugins/spec-workflow/) — the specification-writing skill in action diff --git a/docs/src/content/docs/features/tools.md b/docs/src/content/docs/features/tools.md new file mode 100644 index 0000000..a17fedc --- /dev/null +++ b/docs/src/content/docs/features/tools.md @@ -0,0 +1,234 @@ +--- +title: CLI Tools +description: Reference for all CLI tools and utilities installed in the CodeForge DevContainer. +sidebar: + order: 4 +--- + +CodeForge installs 22 tools and utilities in your DevContainer, covering session management, code quality, language runtimes, and development infrastructure. Every tool is on your `PATH` from the first terminal session — no manual installation required. + +## Session & Claude Tools + +These tools manage your Claude Code sessions, track usage, and provide monitoring capabilities. + +### cc / claude + +Launch Claude Code with the full CodeForge configuration — custom system prompt, all plugins, agents, and skills active. + +```bash +# Start a CodeForge-configured Claude session +cc + +# Equivalent — 'claude' is an alias for the same configuration +claude +``` + +Both `cc` and `claude` set up the CodeForge system prompt, enable plan permission mode, and load all configured plugins. This is the primary way to start Claude Code in a CodeForge environment. + +### ccraw + +Launch Claude Code without any CodeForge configuration — no custom system prompt, no plugins, no agents. Useful for debugging or when you need vanilla Claude Code behavior. + +```bash +# Start vanilla Claude Code +ccraw +``` + +### ccw + +Launch Claude Code with a writing-focused system prompt, optimized for documentation and content creation tasks. + +```bash +# Start Claude in writing mode +ccw +``` + +### ccms — Session History Search + +Search through your Claude Code session history (JSONL files) with boolean queries, role filtering, and time scoping. Built in Rust for fast searching across large session archives. + +```bash +# Basic search across all sessions +ccms "authentication flow" + +# Search within the current project only +ccms --project "$(pwd)" "query" + +# Filter by role — find Claude's past decisions +ccms -r assistant "what was decided about the database schema" + +# Filter by role — find what you previously asked +ccms -r user "auth approach" + +# Boolean queries +ccms "(auth OR authentication) AND NOT test" + +# Time-scoped search +ccms --since "1 day ago" "recent work" +ccms --since "1 week ago" "architecture decisions" + +# JSON output for structured parsing +ccms -f json "query" -n 10 + +# Statistics about your session history +ccms --stats "" + +# Interactive TUI mode (not available from within Claude) +ccms +``` + +:::tip[Project scoping] +Always pass `--project "$(pwd)"` when searching from within a project to avoid results from unrelated projects leaking into your search. +::: + +### ccusage — Usage Statistics + +View your Claude API usage statistics, including token counts, costs, and session summaries. Installed via npm from the [ccusage](https://github.com/ryoppippi/ccusage) project. + +```bash +# View usage statistics +ccusage +``` + +### ccburn — Token Burn Analysis + +Analyze token consumption patterns across sessions to understand usage efficiency and identify sessions with unusually high token burn. + +```bash +# Analyze token burn rate +ccburn +``` + +### claude-dashboard + +A web-based session monitoring dashboard that provides real-time visibility into active Claude sessions, resource usage, and session history. Runs on port 7847. + +```bash +# Launch the dashboard +claude-dashboard +``` + +### claude-monitor + +Real-time terminal-based Claude session monitor. Shows active sessions and their current status. + +```bash +# Start the session monitor +claude-monitor +``` + +### agent-browser + +A headless Chromium browser (Playwright-based) available for agents that need to inspect web content or take screenshots. + +```bash +# Launch the agent browser +agent-browser +``` + +### check-setup + +Verify your CodeForge installation health — checks that all expected tools are installed, plugins are loaded, and configuration is valid. + +```bash +# Run the setup health check +check-setup +``` + +### cc-tools + +List all available CodeForge CLI tools with their installation status and versions. + +```bash +# Show all tools and their status +cc-tools +``` + +This displays a formatted table showing every tool, whether it is installed, and its version number. + +## Code Quality Tools + +These tools are used both manually and automatically by the [Auto Code Quality Plugin](../plugins/auto-code-quality/) to maintain code standards. + +| Command | Languages | Purpose | Example | +|---------|-----------|---------|---------| +| `ruff` | Python | Linting and formatting | `ruff check src/ && ruff format src/` | +| `biome` | JS/TS/JSON | Linting and formatting | `biome check src/` | +| `shellcheck` | Shell | Script linting | `shellcheck scripts/*.sh` | +| `shfmt` | Shell | Script formatting | `shfmt -w scripts/*.sh` | +| `dprint` | MD/TOML/JSON | Formatting | `dprint fmt` | +| `hadolint` | Dockerfile | Linting | `hadolint Dockerfile` | + +:::tip[Automatic quality] +You rarely need to run these tools manually. The Auto Code Quality plugin runs the appropriate linter and formatter automatically when Claude edits files. See [Auto Code Quality](../plugins/auto-code-quality/) for details. +::: + +## Code Intelligence Tools + +| Command | Purpose | Details | +|---------|---------|---------| +| `sg` / `ast-grep` | Structural code search using AST patterns | [Full documentation](./code-intelligence/) | +| `tree-sitter` | Syntax tree parsing and symbol extraction | [Full documentation](./code-intelligence/) | + +These tools are covered in depth on the [Code Intelligence](./code-intelligence/) page. + +## Language Runtimes & Package Managers + +CodeForge includes modern language runtimes and fast package managers so you can work with multiple languages out of the box. + +| Tool | Version | Purpose | Example | +|------|---------|---------|---------| +| **Node.js** | via nvm | JavaScript runtime | `node --version` | +| **Python** | 3.14 via uv | Python runtime | `python --version` | +| **Rust** | via rustup | Rust toolchain | `cargo --version` | +| **Bun** | latest | Fast JS runtime and package manager | `bun install` | +| **uv** | latest | Fast Python package manager | `uv pip install requests` | +| **Go** | via feature | Go toolchain | `go version` | +| **GitHub CLI** (`gh`) | latest | GitHub operations from the terminal | `gh pr create` | + +:::note[uv for Python] +CodeForge uses `uv` as the default Python package manager. It is significantly faster than pip for dependency resolution and installation. Use `uv pip install` instead of `pip install` for the best experience. +::: + +## Development Utilities + +| Tool | Purpose | Example | +|------|---------|---------| +| **tmux** | Terminal multiplexer for session management | `tmux new -s work` | +| **jq** | JSON processor for command-line data manipulation | `cat data.json \| jq '.results[]'` | +| **git** | Version control (pre-configured) | `git log --oneline -10` | +| **docker** | Container management (host Docker socket mounted) | `docker ps` | +| **LSP servers** | Language servers for code intelligence | See [Code Intelligence](./code-intelligence/) | + +## Complete Tool Reference + +| # | Command | Category | Description | +|---|---------|----------|-------------| +| 1 | `cc` / `claude` | Session | Claude Code with CodeForge config | +| 2 | `ccraw` | Session | Vanilla Claude Code | +| 3 | `ccw` | Session | Claude Code in writing mode | +| 4 | `ccms` | Session | Session history search | +| 5 | `ccusage` | Session | API usage statistics | +| 6 | `ccburn` | Session | Token burn analysis | +| 7 | `ccstatusline` | Session | Terminal statusline | +| 8 | `claude-dashboard` | Session | Web-based session dashboard | +| 9 | `claude-monitor` | Session | Real-time session monitor | +| 10 | `agent-browser` | Session | Headless browser for agents | +| 11 | `check-setup` | Session | Installation health check | +| 12 | `cc-tools` | Session | List all available tools | +| 13 | `ruff` | Quality | Python linting and formatting | +| 14 | `biome` | Quality | JS/TS/JSON linting and formatting | +| 15 | `shellcheck` | Quality | Shell script linting | +| 16 | `shfmt` | Quality | Shell script formatting | +| 17 | `dprint` | Quality | Markdown/TOML/JSON formatting | +| 18 | `hadolint` | Quality | Dockerfile linting | +| 19 | `sg` / `ast-grep` | Intelligence | Structural code search | +| 20 | `tree-sitter` | Intelligence | Syntax tree parsing | +| 21 | `pyright` | Intelligence | Python LSP server | +| 22 | `typescript-language-server` | Intelligence | TypeScript/JS LSP server | + +## Related + +- [Code Intelligence](./code-intelligence/) — ast-grep, tree-sitter, and LSP details +- [Commands Reference](../reference/commands/) — complete command table +- [Auto Code Quality](../plugins/auto-code-quality/) — how quality tools are automated diff --git a/docs/src/content/docs/getting-started/first-session.md b/docs/src/content/docs/getting-started/first-session.md new file mode 100644 index 0000000..0ce9ea1 --- /dev/null +++ b/docs/src/content/docs/getting-started/first-session.md @@ -0,0 +1,197 @@ +--- +title: First Session +description: Walkthrough of your first Claude Code session inside a CodeForge DevContainer. +sidebar: + order: 4 +--- + +You've installed CodeForge and the container is running. Now it's time to launch your first Claude Code session and see everything in action. This guide walks you through what happens when you start a session, what to try first, and how the different systems work together. + +## Starting a Session + +Open a terminal inside the DevContainer and launch Claude Code: + +```bash +cc +``` + +The `cc` command is a CodeForge alias that launches Claude Code with the correct system prompt, permission mode, and plugin hooks. It's the recommended way to start every session. + +### Available Launch Commands + +| Command | What It Does | +|---------|-------------| +| `cc` | Full CodeForge session with system prompt, plugins, and all configuration | +| `claude` | Same as `cc` — an alias for convenience | +| `ccw` | Writing-focused session using the writing system prompt (great for documentation) | +| `ccraw` | Raw Claude Code session with no CodeForge configuration — useful for debugging | + +:::tip[When to use ccraw] +If something isn't working as expected in a CodeForge session, try `ccraw` to see if the issue is with CodeForge's configuration or with Claude Code itself. It launches a completely vanilla session with no plugins, system prompts, or hooks. +::: + +## What Happens Automatically + +When your session starts, several systems activate behind the scenes to make Claude smarter and safer. You don't need to configure any of this — it just works. + +### System Prompt Loading + +The main system prompt gives Claude context about your project, coding standards, and behavioral guidelines. It's loaded from your configuration directory and defines how Claude approaches tasks, what tools to prefer, and how to communicate. The prompt is customizable — see [System Prompts](../customization/system-prompts/) for details. + +### Plugin Hook Activation + +Plugins register hooks that fire at specific points during your session. These run automatically and silently in the background: + +**PreToolUse hooks** run before Claude executes a command or edits a file: +- The **workspace scope guard** blocks writes outside your project directory +- The **dangerous command blocker** catches destructive shell commands (`rm -rf /`, `git push --force`, etc.) +- The **protected files guard** prevents edits to secrets, lock files, and other sensitive files + +**PostToolUse hooks** run after a tool completes: +- The **session context** plugin injects git state and TODO information +- The **notify hook** sends a desktop notification when Claude finishes a long task + +**Stop hooks** run when Claude finishes a turn: +- The **spec reminder** checks whether code was modified without updating specs +- The **auto code quality** plugin runs formatting and linting checks +- The **commit reminder** nudges you to commit if there are significant uncommitted changes + +### Session Context Injection + +The session context plugin keeps Claude informed about your working environment. At turn boundaries, it injects: + +- **Git state** — current branch, uncommitted changes, recent commits +- **Active TODOs** — extracted from TODO comments in recently modified files +- **Commit reminders** — when there are significant uncommitted changes + +This means Claude always knows the state of your repository without you having to explain it. + +## What to Try First + +Here are some practical things to try in your first session to see CodeForge's capabilities: + +### Explore Your Codebase + +Ask Claude to understand your project: + +``` +Explore this codebase and explain the architecture. +``` + +Claude delegates to the **explorer agent**, which systematically reads your project structure, key files, and configuration to build a comprehensive understanding. This is a great starting point for any new project. + +### Run a Security Review + +``` +Review the security of the authentication module. +``` + +The **security auditor agent** activates and performs a structured review: checking for common vulnerabilities, reviewing authentication flows, and flagging potential issues with concrete recommendations. + +### Generate Tests + +``` +Write tests for the user service. +``` + +The **test writer agent** generates tests that follow your project's existing patterns. It looks at your test framework, directory structure, and naming conventions before writing anything. + +### Start a Feature with a Spec + +``` +/spec-new +``` + +This skill walks you through creating a feature specification. Specs bring structure to development — you define what you're building before writing code. See the [Spec Workflow plugin](../plugins/spec-workflow/) for the full lifecycle. + +### Check Your Tools + +From the terminal (not inside a Claude session), you can verify what's available: + +```bash +# List all installed tools and their versions +cc-tools + +# Search past session history +ccms "what did we work on" + +# Check API token usage +ccusage + +# Open the session analytics dashboard +claude-dashboard +``` + +## Working with Agents + +CodeForge includes 17 specialized agents. You don't need to know their names — Claude automatically delegates to the right agent based on your request. But understanding what's available helps you make better requests. + +Here are some example interactions and which agents handle them: + +| Your Request | Agent | What It Does | +|-------------|-------|-------------| +| "Explore this codebase" | Explorer | Systematic codebase navigation | +| "Design the API for user management" | Architect | System design and architecture | +| "Debug why the login fails" | Debug Logs | Log analysis and bug investigation | +| "Refactor this module to reduce duplication" | Refactorer | Safe, incremental code transformations | +| "Write a migration from SQLite to PostgreSQL" | Migrator | Database and framework migrations | +| "Profile the performance of the search endpoint" | Perf Profiler | Performance analysis and optimization | +| "Audit this module for vulnerabilities" | Security Auditor | Security review and recommendations | +| "Write documentation for the API" | Doc Writer | Documentation generation | + +Each agent carries domain-specific instructions that guide how Claude approaches the task. For example, the security auditor checks OWASP Top 10 categories, while the test writer respects your project's testing patterns and frameworks. + +See [Agents](../features/agents/) for the full list of all 17 agents and their specializations. + +## Working with Skills + +Skills are domain-specific knowledge packs that Claude draws on when relevant. They're suggested automatically by the skill engine based on what you're working on, or you can invoke them directly with slash commands. + +### Frequently Used Skills + +| Skill | What It Provides | +|-------|-----------------| +| `/spec-new` | Create a new feature specification | +| `/spec-build` | Implement a feature from its spec (plan, build, review, close) | +| `/spec-check` | Audit spec health across the project | +| `/spec-update` | Update specs to match current implementation | + +### Auto-Suggested Skills + +You don't always need to invoke skills manually. The skill engine watches what you're working on and suggests relevant skills. For example: + +- Working on a FastAPI endpoint? The FastAPI skill is suggested with best practices for route design, dependency injection, and error handling +- Writing Docker configuration? The Docker skill provides patterns for multi-stage builds, security hardening, and compose setups +- Debugging a tricky issue? The debugging skill offers systematic approaches to isolate and fix problems + +See [Skills](../features/skills/) for the complete catalog of all 21 available skills. + +## Understanding the Status Line + +If your terminal supports it, CodeForge provides a status line that shows session information at a glance. The `ccstatusline` feature adds session metadata to your terminal prompt, so you always know which session you're in and its current state. + +## Tips for Effective Sessions + +:::tip[Be specific with requests] +Instead of "fix the bug," try "the login endpoint returns 500 when the email field is empty — debug and fix it." More context leads to better results, even though CodeForge gives Claude a lot of context automatically. +::: + +:::tip[Use the spec workflow for features] +For anything beyond a simple bug fix, start with `/spec-new`. Writing a spec first helps Claude (and you) think through the design before writing code. The spec becomes a living document that tracks what was built and why. +::: + +:::tip[Let agents do their thing] +When Claude delegates to a specialized agent, the agent follows its own structured approach. A security audit, for example, systematically checks categories rather than just looking at what seems obvious. Trust the process — the structured approach catches things that ad-hoc reviews miss. +::: + +:::caution[Watch for commit reminders] +The session context plugin reminds you to commit when there are significant uncommitted changes. Don't ignore these — frequent commits make it easy to review and revert changes. Claude can help you write commit messages too. +::: + +## Next Steps + +- [Plugins Overview](../plugins/) — understand how each plugin enhances your workflow +- [Agents](../features/agents/) — explore all 17 specialized agents in detail +- [Skills](../features/skills/) — browse the complete skill catalog +- [Configuration](../customization/configuration/) — customize CodeForge to match your preferences +- [Commands Reference](../reference/commands/) — full reference for all CLI commands diff --git a/docs/src/content/docs/getting-started/index.md b/docs/src/content/docs/getting-started/index.md new file mode 100644 index 0000000..c790056 --- /dev/null +++ b/docs/src/content/docs/getting-started/index.md @@ -0,0 +1,100 @@ +--- +title: Getting Started +description: Quick start guide to setting up CodeForge for AI-assisted development with Claude Code. +sidebar: + order: 1 +--- + +CodeForge is a DevContainer configuration that transforms your development environment into an AI-powered workspace. It bundles 12 plugins, 21 tools, 17 specialized agents, and 21 skills into a single `npx codeforge-dev` install. + +## What is CodeForge? + +CodeForge provides a fully configured DevContainer for AI-assisted development with Claude Code. Instead of spending hours wiring up linters, formatters, language servers, and shell aliases, you get a single command that installs everything and configures it to work together out of the box. + +Inside the container, Claude Code gains superpowers: specialized agents handle architecture reviews, security audits, and test generation, while plugins enforce workspace safety, inject session context, and manage specification-driven workflows. The result is a development environment where AI assistance is deeply integrated, not bolted on. + +## Quick Install + +```bash +npx codeforge-dev +``` + +This sets up the `.devcontainer/` configuration in your project. Open the project in VS Code and reopen in the container when prompted. That's it — your AI-powered workspace is ready. + +:::tip[Try it in under five minutes] +If you already have Docker and VS Code installed, you can go from zero to a running CodeForge session in under five minutes. See the [Installation Guide](./installation/) for the full walkthrough. +::: + +## Why CodeForge? + +**Start productive immediately.** New projects and new team members skip the setup ritual entirely. One command installs a complete, consistent environment with every tool pre-configured. + +**AI that understands your workflow.** CodeForge doesn't just install Claude Code — it teaches it. System prompts, plugin hooks, and rules give Claude deep context about your project structure, coding standards, and preferred workflows. The agent system provides 17 specialized AI agents, each tuned for a specific task like architecture planning, debugging, or security auditing. + +**Safety built in.** Workspace scope guards prevent accidental writes outside your project directory. Dangerous command blockers catch destructive shell commands before they run. Protected file guards keep secrets and lock files safe. You get the power of AI-assisted development with guardrails that prevent costly mistakes. + +**Specification-driven development.** The spec workflow plugin brings structure to feature development. Write a spec, refine it with your team, build from it, and keep it updated as-built — all with dedicated skills that guide each step. + +## What's Included + +### 12 Plugins + +Plugins are the backbone of CodeForge. They hook into Claude Code's lifecycle to enhance, guard, and automate your workflow. Highlights include: + +- **Agent System** — 17 specialized agents for architecture, debugging, testing, security, and more +- **Skill Engine** — 21 domain-specific knowledge packs covering frameworks, patterns, and workflows +- **Spec Workflow** — specification-driven development with 8 lifecycle skills +- **Session Context** — automatic git state injection, TODO harvesting, and commit reminders +- **Auto Code Quality** — formatting, linting, and advisory test runs on every change +- **Safety Guards** — workspace scope, dangerous command blocking, and protected file enforcement + +See the [Plugins Overview](../plugins/) for the full list and detailed documentation. + +### 21 Features and Tools + +CodeForge installs a comprehensive toolchain so you never have to stop and install something mid-session: + +- **Language Runtimes** — Python 3.14, Node.js LTS, Rust, Bun, with Go available as an opt-in +- **Package Managers** — uv (Python), npm, Bun, pip/pipx +- **Code Intelligence** — tree-sitter, ast-grep, Pyright, TypeScript LSP +- **Linters and Formatters** — Ruff, Biome, shfmt, ShellCheck, hadolint, dprint +- **CLI Utilities** — GitHub CLI, Docker, jq, tmux, and CodeForge-specific tools like ccms, ccusage, and ccburn + +See the [Features Overview](../features/) for the complete reference. + +### 17 Custom Agents + +Agents are specialized AI personas that Claude delegates to based on your request. Each agent carries domain-specific instructions and behavioral guidelines: + +- **Architect** — system design, dependency analysis, and architecture decisions +- **Explorer** — codebase navigation and structural understanding +- **Test Writer** — test generation with framework-aware patterns +- **Security Auditor** — vulnerability detection and security review +- **Refactorer** — safe, incremental code transformations +- And 12 more covering debugging, documentation, migration, performance, and beyond + +See [Agents](../features/agents/) for the full roster. + +### 21 Skills + +Skills are domain-specific knowledge packs that Claude can draw on. They provide curated best practices, patterns, and workflows for specific technologies and tasks: + +- **Framework skills** — FastAPI, Svelte 5, Pydantic AI, Docker +- **Pattern skills** — API design, refactoring, migration, testing +- **Workflow skills** — specification writing, debugging, dependency management, git forensics + +See [Skills](../features/skills/) for the complete catalog. + +## How It All Fits Together + +When you launch a session with the `cc` command, CodeForge loads your system prompt, activates all enabled plugins, and registers their hooks. As you work, plugins fire at key moments — before a tool runs, after a tool completes, and when Claude finishes a turn. Agents and skills are surfaced automatically based on what you're working on, or you can invoke them directly. + +The environment is designed to stay out of your way while quietly making everything better: session context appears when you need it, dangerous commands get blocked before they cause damage, and specs stay in sync with your implementation. + +## Next Steps + +- [System Requirements](./requirements/) — verify your system is ready +- [Installation Guide](./installation/) — detailed setup instructions +- [First Session](./first-session/) — walk through your first Claude Code session +- [Plugins Overview](../plugins/) — explore the plugin ecosystem +- [Features Overview](../features/) — browse available agents, skills, and tools diff --git a/docs/src/content/docs/getting-started/installation.md b/docs/src/content/docs/getting-started/installation.md new file mode 100644 index 0000000..3c13464 --- /dev/null +++ b/docs/src/content/docs/getting-started/installation.md @@ -0,0 +1,213 @@ +--- +title: Installation +description: Step-by-step guide to installing and configuring CodeForge in your project. +sidebar: + order: 3 +--- + +This guide walks you through setting up CodeForge from scratch. The process has three steps: run the installer, open the container, and verify. Most of the heavy lifting happens automatically. + +## Step 1: Install CodeForge + +Navigate to your project root and run: + +```bash +npx codeforge-dev +``` + +This creates a `.devcontainer/` directory containing the full CodeForge configuration — all plugins, features, agents, skills, system prompts, and settings. Your existing project files are not modified. + +:::tip[Already have a .devcontainer?] +If your project already has a `.devcontainer/` directory, the installer will warn you and exit. Use the `--force` flag to perform a smart sync that preserves your user configuration: +```bash +npx codeforge-dev --force +``` +The `--force` flag uses an intelligent sync — it preserves files you've customized (creating `.codeforge-new` diff files for review) rather than blindly overwriting everything. +::: + +### Alternative Installation Methods + +```bash +# Install globally for repeated use +npm install -g codeforge-dev +codeforge-dev + +# Pin a specific version +npx codeforge-dev@1.14.0 +``` + +### What the Installer Creates + +After running the installer, your project will have: + +``` +your-project/ +├── .devcontainer/ +│ ├── devcontainer.json # Container definition and feature list +│ ├── .env # Setup flags +│ ├── config/ +│ │ ├── file-manifest.json # Controls config file deployment +│ │ └── defaults/ # System prompts, settings, rules +│ ├── features/ # 21 custom DevContainer features +│ ├── plugins/ # 12 plugins with hooks and scripts +│ └── scripts/ # Setup and verification scripts +└── ... (your existing files) +``` + +## Step 2: Open in VS Code + +Open your project in VS Code. You should see a notification in the bottom-right corner: + +> **Folder contains a Dev Container configuration file.** Reopen folder to develop in a container. + +Click **Reopen in Container**. If you miss the notification, use the Command Palette: + +1. Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS) +2. Type "Dev Containers" and select **Dev Containers: Reopen in Container** + +### What Happens During the First Build + +The first container build takes several minutes (typically 3-8 minutes depending on your internet speed and hardware). Here's what's happening behind the scenes: + +1. **Base image pull** — downloads the Python 3.14 DevContainer image from Microsoft's registry +2. **Feature installation** — installs 21 DevContainer features in dependency order: Node.js and uv first (other tools depend on them), then Rust, Bun, Claude Code, and all custom features +3. **Post-start setup** — deploys configuration files, sets up shell aliases, and configures plugins + +You can watch the progress in VS Code's log output. Look for the "Dev Containers" output channel in the terminal panel. + +:::caution[Don't interrupt the first build] +If the build is interrupted, Docker may cache a partial state. Use **Dev Containers: Rebuild Container Without Cache** to start fresh. +::: + +## Step 3: Verify Installation + +Once the container is running and you have a terminal prompt, verify everything installed correctly: + +```bash +check-setup +``` + +This command checks that all tools, runtimes, and plugins are in place. You should see green checkmarks for each component. + +For a more detailed view of every installed tool and its version: + +```bash +cc-tools +``` + +This lists every command CodeForge provides, along with its version number or installation status. + +### Expected Output + +A healthy installation shows all of these as available: + +| Category | Tools | +|----------|-------| +| Claude Code | `claude`, `cc`, `ccw`, `ccraw` | +| Session tools | `ccms`, `ccusage`, `ccburn`, `claude-monitor` | +| Languages | `node`, `python`, `rustc`, `bun` | +| Code intelligence | `ast-grep`, `tree-sitter`, `pyright`, `typescript-language-server` | +| Linters/Formatters | `ruff`, `biome` | +| Utilities | `gh`, `docker`, `git`, `jq`, `tmux` | + +:::note[Some tools are optional] +A few features ship with `"version": "none"` by default (shfmt, dprint, shellcheck, hadolint). These are available but disabled. Enable them by changing the version in `devcontainer.json` and rebuilding the container. +::: + +## What Gets Installed + +### Language Runtimes + +- **Python 3.14** — the container's base image, with `uv` as the package manager +- **Node.js LTS** — installed via nvm, with npm included +- **Rust** — latest stable via rustup +- **Bun** — fast JavaScript/TypeScript runtime and package manager +- **Go** — available as an opt-in (uncomment in `devcontainer.json`) + +### CLI Tools + +- **GitHub CLI** (`gh`) — repository management, PR creation, issue tracking +- **Docker** (Docker-outside-of-Docker) — container operations from inside the DevContainer +- **tmux** — terminal multiplexing for parallel Claude Code sessions +- **ccms** — search your Claude Code session history +- **ccusage** / **ccburn** — token usage analysis and burn rate tracking +- **ccstatusline** — session status in your terminal prompt +- **claude-monitor** — real-time session monitoring +- **claude-dashboard** — web-based session analytics on port 7847 +- **agent-browser** — headless Chromium via Playwright for web interaction +- **ast-grep** / **tree-sitter** — structural code search and parsing + +### Plugins + +All 12 plugins are installed and active by default. They're configured through `settings.json` and managed by the plugin system. See the [Plugins Overview](../plugins/) for details on each plugin and how to enable or disable them. + +## Configuration + +CodeForge works out of the box, but everything is customizable: + +- **`devcontainer.json`** — container image, features, resource limits, port forwarding +- **`config/defaults/settings.json`** — model selection, permissions, enabled plugins, environment variables +- **`config/defaults/main-system-prompt.md`** — Claude Code's behavioral guidelines +- **`config/defaults/rules/`** — rules loaded into every session automatically + +See the [Customization section](../customization/) for full details on each configuration surface. + +## Updating CodeForge + +To update to the latest version: + +```bash +npx codeforge-dev@latest +``` + +This updates the `.devcontainer/` configuration. After updating, rebuild the container: + +1. Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS) +2. Select **Dev Containers: Rebuild Container** + +:::tip[Check what changed] +Use `git diff .devcontainer/` after updating to review what changed before committing. This lets you verify the update didn't overwrite any customizations you want to keep. +::: + +## Troubleshooting + +### Container fails to build + +**Symptoms:** VS Code shows a build error, or the container exits immediately. + +**Common causes and fixes:** + +- **Docker not running** — start Docker Desktop or the Docker daemon +- **Insufficient resources** — open Docker Desktop settings and allocate at least 4 GB RAM and 20 GB disk to the VM +- **Network issues** — the first build downloads several GB of images and tools; check your internet connection +- **Cached partial build** — use **Dev Containers: Rebuild Container Without Cache** to start clean + +### Tools not found after build + +**Symptoms:** Commands like `cc` or `ccms` return "command not found." + +- Run `check-setup` to identify which tools are missing +- Check that the post-start script completed successfully (look for errors in the terminal output) +- Rebuild the container to trigger a fresh install + +### Claude Code authentication issues + +**Symptoms:** Running `cc` or `claude` prompts for authentication or returns an error. + +- Claude Code authenticates on first launch — follow the prompts to sign in +- If authentication was previously completed but stopped working, try `claude auth` to re-authenticate +- Ensure your Claude subscription is active + +### Slow container startup + +**Symptoms:** The container takes a long time to start after the initial build. + +- Subsequent starts should be fast (under 30 seconds) because Docker caches built layers +- If starts are consistently slow, check Docker resource allocation +- The `postStartCommand` runs on every start to deploy configuration files — this is normal and should complete in a few seconds + +## Next Steps + +- [First Session](./first-session/) — start using CodeForge with Claude Code +- [Configuration](../customization/configuration/) — customize settings +- [Plugins Overview](../plugins/) — understand what each plugin does diff --git a/docs/src/content/docs/getting-started/requirements.md b/docs/src/content/docs/getting-started/requirements.md new file mode 100644 index 0000000..a651e72 --- /dev/null +++ b/docs/src/content/docs/getting-started/requirements.md @@ -0,0 +1,117 @@ +--- +title: System Requirements +description: Prerequisites and system requirements for running CodeForge DevContainers. +sidebar: + order: 2 +--- + +Before installing CodeForge, make sure your system meets the requirements below. The good news: if you already have Docker and VS Code, you're most of the way there. CodeForge handles the rest automatically inside the container. + +## Required Software + +### Docker + +CodeForge runs inside a DevContainer, which requires a container runtime. You need one of the following: + +| Platform | Runtime | Recommended Version | +|----------|---------|-------------------| +| macOS | Docker Desktop | 4.x or later | +| Windows | Docker Desktop with WSL 2 backend | 4.x or later | +| Linux | Docker Engine | 24.x or later | + +Docker Desktop is the simplest option on macOS and Windows — it bundles everything you need. On Linux, Docker Engine works well and avoids the Docker Desktop license requirements for larger organizations. + +:::tip[Check your Docker installation] +Run `docker info` in your terminal. If you see container and image counts, Docker is ready. If you get a connection error, the Docker daemon isn't running — start Docker Desktop or run `sudo systemctl start docker` on Linux. +::: + +:::caution[Windows users] +WSL 2 is required. Docker Desktop's legacy Hyper-V backend is not supported because DevContainers rely on WSL 2 for Linux container support. If you haven't enabled WSL 2, follow [Microsoft's WSL installation guide](https://learn.microsoft.com/en-us/windows/wsl/install) before proceeding. +::: + +### VS Code + +- **Visual Studio Code** — version 1.85 or later +- **Dev Containers extension** — install `ms-vscode-remote.remote-containers` from the Extensions marketplace + +The Dev Containers extension is what makes VS Code able to open your project inside the container. Without it, the "Reopen in Container" prompt won't appear. + +:::note[Alternative: GitHub Codespaces] +If you prefer not to run Docker locally, you can use GitHub Codespaces. Push your project (with the `.devcontainer/` directory) to GitHub and create a Codespace from it. Codespaces use the same DevContainer configuration, so everything works the same way. +::: + +### Claude Code + +CodeForge is built around Claude Code, so you need: + +- An active **Claude Pro**, **Claude Max**, or **Claude API** subscription +- The `claude` CLI installed and authenticated — CodeForge installs it automatically inside the container, but you'll need to authenticate on first launch + +You'll authenticate Claude Code during your first session. The container handles installation; you just need valid credentials. + +## Hardware Recommendations + +CodeForge runs a full development environment inside a container, including language runtimes, language servers, and CLI tools. The container is configured with a 6 GB memory limit and 12 GB swap by default. + +### Minimum + +| Resource | Requirement | +|----------|-------------| +| RAM | 8 GB | +| Disk space | 20 GB free (container images, tool caches, runtimes) | +| CPU | 2 cores | + +These minimums will get you running, but expect slower container builds and some lag when multiple language servers are active. + +### Recommended + +| Resource | Requirement | +|----------|-------------| +| RAM | 16 GB or more | +| Disk space | 40 GB free | +| CPU | 4+ cores | + +With 16 GB of RAM and a modern processor, the container runs smoothly and builds complete in a few minutes. More disk space helps if you work on multiple projects with separate container images. + +:::tip[Docker resource allocation] +On macOS and Windows, Docker Desktop runs inside a VM with its own resource limits. Open Docker Desktop settings and check that the VM has at least 4 GB RAM and 20 GB disk allocated. The container itself is configured with `--memory=6g --memory-swap=12g`, so your Docker VM needs headroom above that. +::: + +## Operating System Support + +| OS | Version | Notes | +|----|---------|-------| +| macOS | 12 (Monterey) or later | Intel and Apple Silicon both supported | +| Linux | Ubuntu 22.04+, Debian 12+, Fedora 38+ | Or any distribution with Docker Engine 24+ | +| Windows | Windows 10/11 with WSL 2 | Docker Desktop required | + +## Network Requirements + +**During initial setup**, internet access is required to: + +- Pull the base container image (`mcr.microsoft.com/devcontainers/python:3.14`) +- Install DevContainer features (Node.js, Rust, Bun, uv, and 20+ custom features) +- Download CLI tools and language servers + +The first build downloads roughly 2-4 GB depending on what's cached. Subsequent container starts are much faster because Docker caches the built layers. + +**After setup**, most features work offline. A few tools require connectivity: + +- GitHub CLI (`gh`) — for repository operations +- Web search and API calls — if used during Claude Code sessions +- `ccusage` / `ccburn` — for usage data retrieval + +## Verifying Your Setup + +Once you've confirmed the prerequisites, you're ready to install. After installation, CodeForge provides a built-in health check: + +```bash +check-setup +``` + +This command validates that all tools, runtimes, and plugins installed correctly. Run it any time you suspect something is misconfigured. + +## Next Steps + +- [Installation Guide](./installation/) — proceed with setup +- [First Session](./first-session/) — what to expect in your first session diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx new file mode 100644 index 0000000..486eef7 --- /dev/null +++ b/docs/src/content/docs/index.mdx @@ -0,0 +1,18 @@ +--- +title: CodeForge +description: The complete Claude Code development environment. 12 plugins, 21 tools, 17 AI agents — battle-tested and ready to go. +template: splash +hero: + tagline: Your AI dev environment, battle-tested. + actions: + - text: Get Started + link: /CodeForge/getting-started/ + icon: right-arrow + variant: primary + - text: View on GitHub + link: https://github.com/AnExiledDev/CodeForge + icon: external + variant: minimal +--- + +{/* Hero content is rendered by the custom Hero.astro component override. */} diff --git a/docs/src/content/docs/plugins/agent-system.md b/docs/src/content/docs/plugins/agent-system.md new file mode 100644 index 0000000..bfe54c6 --- /dev/null +++ b/docs/src/content/docs/plugins/agent-system.md @@ -0,0 +1,239 @@ +--- +title: Agent System +description: The agent system plugin provides 17 specialized AI agents with automatic delegation, CWD injection, and read-only enforcement. +sidebar: + order: 2 +--- + +The agent system is CodeForge's flagship plugin. It gives you access to 17 specialized AI agents, each purpose-built for a specific kind of development task — from architecture planning and code exploration to test writing and security auditing. When you make a request, the system automatically delegates to the most appropriate agent, so you get expert-level results without having to think about which tool to use. + +## How Delegation Works + +When you ask Claude to do something, the agent system analyzes your request and routes it to the specialist best suited for the job. Each agent carries its own system prompt, tool restrictions, permission mode, and domain expertise. This means an architecture question goes to an agent that thinks in terms of system design, while a "write tests for this" request goes to an agent that knows testing frameworks inside and out. + +Delegation happens transparently. You just describe what you need, and the right agent picks it up. Here are some examples: + +- **"Plan the implementation for user notifications"** routes to the **architect** agent, which explores the codebase, identifies patterns, and produces a structured plan — without modifying any files +- **"Find all API endpoint definitions"** routes to the **explorer** agent, which uses Glob, Grep, and ast-grep to efficiently discover and map code +- **"Write tests for the auth module"** routes to the **test-writer** agent, which detects your test framework, studies existing conventions, writes comprehensive tests, and verifies they pass +- **"Refactor this function to reduce complexity"** routes to the **refactorer** agent, which works in a git worktree and runs regression checks after every edit + +:::tip[You Can Be Specific] +While automatic delegation works well for most requests, you can always ask for a specific agent by name: "Use the security-auditor to review this endpoint" or "Have the architect plan this migration." +::: + +### What Makes Agents Different From Regular Prompts + +Each agent is more than just a system prompt. Agents carry: + +- **Tool restrictions** — read-only agents physically cannot modify files. The explorer, architect, and researcher agents have their write tools removed entirely. +- **Permission modes** — some agents run in `plan` mode (read-only), others in `acceptEdits` (can write with approval), and the generalist inherits the session's default. +- **Frontloaded skills** — agents come pre-loaded with relevant skills. The architect gets `api-design` and spec skills. The test-writer gets the `testing` skill. This domain knowledge is available immediately without manual activation. +- **Custom hooks** — agents can register their own hooks. The refactorer runs `verify-no-regression.py` after every edit. The test-writer runs `verify-tests-pass.py` at the end of every turn. +- **Isolation** — destructive agents like the refactorer and test-writer work in git worktrees, keeping your main branch clean until changes are verified. + +## Built-In Agent Redirection + +One of CodeForge's most distinctive features is that it **completely replaces Claude Code's built-in agents** with enhanced custom specialists. This is not a prompt-level suggestion — it is a hook-level interception that guarantees every agent spawn uses a CodeForge specialist instead of a stock agent. + +### How It Works + +The `redirect-builtin-agents.py` script registers as a `PreToolUse` hook on the `Task` tool. Every time Claude spawns a subagent, the hook fires before the agent is created: + +1. The hook reads the requested `subagent_type` from the Task tool input +2. It checks the type against a redirect map of built-in → custom agent mappings +3. If the type matches a built-in agent, the hook rewrites the `subagent_type` to the fully-qualified custom agent name (e.g., `Explore` becomes `agent-system:explorer`) +4. The modified request proceeds, and the custom agent spawns instead of the stock one +5. All other parameters — the prompt, description, and context — pass through unchanged + +The redirect map covers all six of Claude Code's built-in agent types: + +```python +REDIRECT_MAP = { + "Explore": "explorer", + "Plan": "architect", + "general-purpose": "generalist", + "Bash": "bash-exec", + "claude-code-guide": "claude-guide", + "statusline-setup": "statusline-config", +} +``` + +### What the Upgrade Delivers + +Each redirect is a strict improvement. The custom agents carry capabilities that stock agents lack: + +- **Frontloaded skills** — the architect loads `api-design`, the explorer loads `ast-grep-patterns`, the claude-guide loads `claude-code-headless` and `claude-agent-sdk`. Stock agents load nothing. +- **Calibrated models** — the architect uses Opus for deep reasoning, the explorer uses Haiku for speed. Stock agents all inherit the session default. +- **Safety hooks** — read-only agents have `guard-readonly-bash.py` blocking write operations. The refactorer runs regression checks after every edit. Stock agents have no per-agent safety enforcement. +- **Focused system prompts** — each custom agent has a detailed system prompt shaping its behavior, expertise boundaries, and workflow. Stock agents use a generic prompt. +- **Worktree isolation** — the test-writer, refactorer, migrator, and doc-writer work in isolated git worktrees. Stock agents always work on the active branch. + +The redirect is fully transparent to you and to Claude. Using either name works — `Explore` and `explorer` both resolve to the same enhanced agent. + +:::note[The Seventh Agent Type] +Claude Code has a seventh built-in agent type, `magic-docs`, used internally for documentation updates. This agent is **not** redirected — it runs natively. All other six built-in types are intercepted and replaced. +::: + +## Safety Mechanisms + +The agent system includes two key safety mechanisms that run automatically. + +### CWD Injection + +Every time a subagent starts, the `inject-cwd.py` hook fires. It reads the current working directory and injects it as context for the agent, ensuring every agent knows exactly which project directory to work in. This prevents agents from accidentally operating in the wrong directory — a subtle but important safeguard when working across multiple projects. + +The hook fires on the `SubagentStart` event and adds a message like: *"Working Directory: /workspaces/projects/MyApp — restrict all file operations to this directory."* + +### Read-Only Enforcement + +Agents marked as read-only (architect, explorer, researcher, and others) are protected by `guard-readonly-bash.py`. This hook intercepts every Bash command before execution and blocks anything that would modify state. + +The guard is thorough. It blocks: + +- **File mutations** — `rm`, `mv`, `cp`, `mkdir`, `touch`, `chmod`, and dozens more +- **Git writes** — `git push`, `git commit`, `git merge`, `git reset`, and other state-changing git commands +- **Package managers** — `pip install`, `npm install`, `cargo install`, and similar +- **Redirections** — output redirection (`>`, `>>`) that would create or overwrite files +- **Bypass attempts** — command chaining (`&&`, `||`, `;`), piping into interpreters (`curl | bash`), command substitution (`$(rm file)`), and path-prefixed commands (`/usr/bin/rm`) + +The guard supports two modes: `general-readonly` (blocklist approach — blocks known write commands) and `git-readonly` (allowlist approach — only permits specific safe commands like `git log`, `git diff`, `git blame`, and a curated set of read-only utilities). + +:::caution[Read-Only Is Enforced, Not Requested] +Read-only agents don't just have instructions saying "don't write files." The guard script actively intercepts and blocks write operations at the hook level. Even if an agent's system prompt were ignored, the hook would still prevent modifications. +::: + +## Agent Reference + +CodeForge includes 17 specialized agents. Each one is tailored for a specific class of development task. + +### Read-Only Agents + +These agents investigate, analyze, and report — they never modify files. + +| Agent | Role | Model | Skills | +|-------|------|-------|--------| +| **architect** | System design, implementation planning, trade-off analysis | Opus | api-design, spec skills | +| **explorer** | Fast codebase navigation, file discovery, pattern matching | Haiku | ast-grep-patterns | +| **researcher** | Deep investigation, information gathering, web research | Sonnet | documentation-patterns | +| **claude-guide** | Claude Code usage guidance and best practices | Haiku | claude-code-headless, claude-agent-sdk | +| **debug-logs** | Log analysis, error diagnosis, debugging | Sonnet | debugging | +| **dependency-analyst** | Dependency analysis, version conflicts, upgrade paths | Haiku | dependency-management | +| **git-archaeologist** | Git history analysis, blame, bisect, forensics | Haiku | git-forensics | +| **perf-profiler** | Performance profiling, bottleneck identification | Sonnet | performance-profiling | +| **security-auditor** | Security audit, vulnerability assessment, OWASP checks | Sonnet | security-checklist | +| **spec-writer** | Specification authoring and refinement | Opus | specification-writing | + +### Full-Access Agents + +These agents can read and write files, run commands, and make changes to your codebase. + +| Agent | Role | Model | Isolation | Skills | +|-------|------|-------|-----------|--------| +| **generalist** | General-purpose development tasks | Inherited | No | spec skills | +| **test-writer** | Test creation, coverage analysis, framework detection | Opus | Worktree | testing | +| **refactorer** | Behavior-preserving code transformations | Opus | Worktree | refactoring-patterns | +| **doc-writer** | Documentation writing and maintenance | Opus | Worktree | documentation-patterns | +| **migrator** | Code migration, framework upgrades | Opus | Worktree | migration-patterns | +| **bash-exec** | Shell command execution and scripting | Sonnet | No | — | +| **statusline-config** | Statusline customization | Sonnet | No | — | + +:::note[Model Selection] +Agents use different Claude models based on task complexity. The architect, test-writer, refactorer, doc-writer, migrator, and spec-writer use Opus for maximum reasoning capability. The explorer, dependency-analyst, and git-archaeologist use Haiku for speed. The researcher, security-auditor, debug-logs, perf-profiler, bash-exec, and statusline-config use Sonnet for balanced performance. The generalist inherits the session's model setting. +::: + +## Hook Scripts + +The agent system registers hooks across several lifecycle events: + +| Script | Event | What It Does | +|--------|-------|-------------| +| `redirect-builtin-agents.py` | PreToolUse (Task) | Redirects built-in agent types to CodeForge's custom specialists | +| `inject-cwd.py` | SubagentStart | Injects the working directory so agents operate in the correct project | +| `guard-readonly-bash.py` | PreToolUse (Bash) | Blocks write operations for read-only agents | +| `verify-no-regression.py` | PostToolUse (Edit) | Checks for test regressions after code edits (refactorer) | +| `verify-tests-pass.py` | Stop | Validates all tests pass at the end of a turn (test-writer) | +| `task-completed-check.py` | TaskCompleted | Verifies task results meet requirements in team workflows | +| `teammate-idle-check.py` | TeammateIdle | Monitors teammate activity and reassigns work if needed | + +## How Agent Definitions Work + +Each agent is defined as a Markdown file in the plugin's `agents/` directory. The file's YAML frontmatter configures the agent's technical properties, while the Markdown body contains the agent's system prompt. + +Here is a simplified example of what an agent definition looks like: + +```yaml +--- +name: architect +description: >- + Read-only software architect agent that designs implementation plans... +tools: Read, Glob, Grep, Bash, WebSearch, WebFetch +model: opus +permissionMode: plan +skills: + - api-design + - spec-new +hooks: + PreToolUse: + - matcher: Bash + type: command + command: "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/guard-readonly-bash.py --mode general-readonly" +--- + +# Architect Agent + +You are a **senior software architect** specializing in implementation planning... +``` + +The `tools` field controls which tools the agent can access. The `permissionMode` sets the approval level. The `hooks` section registers agent-specific hooks that only fire for that particular agent. The `skills` field pre-loads domain knowledge. + +The frontmatter also supports several other configuration options: + +| Field | Purpose | Example Values | +|-------|---------|----------------| +| `model` | Which Claude model the agent uses | `opus`, `sonnet`, `haiku`, `inherit` | +| `color` | Agent identifier color in the UI | `magenta`, `blue`, `green`, `yellow` | +| `permissionMode` | Tool approval level | `plan`, `acceptEdits`, `default` | +| `isolation` | Whether the agent works in a git worktree | `worktree` (or omitted for no isolation) | +| `memory` | Memory persistence scope | `project` | +| `disallowedTools` | Tools explicitly blocked for the agent | `EnterPlanMode`, `TeamCreate` | + +### Project Context Discovery + +Every agent follows a standardized project context discovery process before starting work. This ensures agents respect project-specific conventions, tech stack choices, and architectural boundaries: + +1. **Read Claude Rules** — agents scan `.claude/rules/*.md` for mandatory constraints like workspace scoping and spec workflow rules +2. **Read CLAUDE.md files** — agents walk up the directory tree reading `CLAUDE.md` files at each level, where more specific files take precedence over general ones +3. **Apply conventions** — naming patterns, framework choices, architecture boundaries, and workflow rules discovered in these files override the agent's defaults + +This discovery process is particularly important because it means agents adapt to your project rather than applying generic patterns. + +## Team Workflows + +The agent system supports multi-agent team workflows for complex tasks. When a task is too large for a single agent, the system can spawn a team of specialists that work in parallel on different aspects of the problem. + +For example, implementing a feature from a specification might involve: +- A **researcher** exploring the codebase for patterns and conventions +- A **test-writer** creating tests in a worktree +- A **doc-writer** updating documentation + +The team is coordinated through the task system, with hooks like `task-completed-check.py` and `teammate-idle-check.py` ensuring smooth collaboration. + +The recommended team compositions vary by task type: + +| Task Type | Recommended Teammates | +|-----------|----------------------| +| Full-stack feature | researcher + test-writer + doc-writer | +| Backend-heavy work | researcher + test-writer | +| Security-sensitive feature | security-auditor + test-writer | +| Refactoring | refactorer + test-writer | +| Multi-service change | researcher per service + test-writer | + +See the [Spec Workflow](./spec-workflow/) plugin for how team spawning integrates with specification-driven development. + +## Related + +- [Agents Reference](../features/agents/) — detailed per-agent documentation with usage examples +- [Skills Reference](../features/skills/) — skills that agents leverage for domain expertise +- [Hooks](../customization/hooks/) — how hook scripts integrate with the agent lifecycle +- [Skill Engine](./skill-engine/) — the plugin that manages skill auto-suggestion diff --git a/docs/src/content/docs/plugins/auto-code-quality.md b/docs/src/content/docs/plugins/auto-code-quality.md new file mode 100644 index 0000000..49494ce --- /dev/null +++ b/docs/src/content/docs/plugins/auto-code-quality.md @@ -0,0 +1,115 @@ +--- +title: Auto Code Quality +description: The auto code quality plugin runs formatting and linting checks automatically during development sessions. +sidebar: + order: 6 +--- + +The auto code quality plugin keeps your code clean without any manual effort. Every file you edit gets automatically formatted and linted at the end of each assistant turn, so you never need to remember to run your formatters or worry about style inconsistencies creeping in. + +## How It Works + +The plugin operates in four phases during a session, each triggered by a different hook: + +1. **On every edit** (PostToolUse) -- When Claude writes or edits a file, the plugin records the file path and validates data file syntax immediately. +2. **At the end of each turn** (Stop) -- All edited files are batch-formatted using the appropriate tool for each language. +3. **After formatting** (Stop) -- All edited files are linted and any issues are reported. +4. **After linting** (Stop) -- If a test framework is detected, affected tests are run automatically. + +This "collect, then batch process" approach avoids running formatters on every keystroke while ensuring nothing slips through. + +### The Advisory Pattern + +Quality checks run as advisory hooks -- they report findings without blocking your workflow. Formatting is applied silently, while lint warnings and test failures are surfaced as context that Claude can act on. If tests fail, the hook blocks the Stop so Claude addresses the failures before finishing. + +## Phase 1: Syntax Validation + +When you edit a data file (JSON, JSONC, YAML, or TOML), the `syntax-validator.py` script validates it immediately. This catches broken configuration files the moment they're saved rather than waiting for something downstream to fail. + +Validated formats: + +| Format | Validation | +|--------|------------| +| `.json` | JSON parse check | +| `.jsonc` | Comment-stripped JSON parse check | +| `.yaml` / `.yml` | YAML safe_load (requires PyYAML) | +| `.toml` | TOML parse check (Python 3.11+) | + +## Phase 2: Auto-Formatting + +At the end of each turn, `format-on-stop.py` processes every file that was edited during the conversation. It selects the right formatter based on file extension: + +| Formatter | Languages / Extensions | Notes | +|-----------|----------------------|-------| +| **Ruff** (or Black fallback) | `.py`, `.pyi` | Ruff preferred; falls back to Black if unavailable | +| **gofmt** | `.go` | Standard Go formatting | +| **Biome** | `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.mts`, `.cts`, `.css`, `.json`, `.jsonc`, `.graphql`, `.gql`, `.html`, `.vue`, `.svelte`, `.astro` | Checks project-local install first, then global | +| **shfmt** | `.sh`, `.bash`, `.zsh`, `.mksh`, `.bats` | Shell script formatting | +| **dprint** | `.md`, `.markdown`, `.yaml`, `.yml`, `.toml`, `Dockerfile` | Uses global dprint config | +| **rustfmt** | `.rs` | Conditional -- only runs if installed | + +:::tip[Project-Local Tools] +For Biome, the formatter checks your project's `node_modules/.bin/` first before falling back to the global install. This means your project's Biome version and configuration are respected automatically. +::: + +## Phase 3: Auto-Linting + +After formatting, `lint-file.py` runs language-appropriate linters on the same set of edited files: + +| Linter | Languages | What It Catches | +|--------|-----------|-----------------| +| **Pyright** | Python | Type errors, missing imports, incorrect signatures | +| **Ruff** | Python | Style violations, unused imports, correctness issues | +| **Biome** | JS/TS/CSS/GraphQL | Lint rules, accessibility, suspicious patterns | +| **ShellCheck** | Shell scripts | Common shell scripting pitfalls, quoting issues | +| **go vet** | Go | Suspicious constructs, printf format mismatches | +| **hadolint** | Dockerfile | Dockerfile best practices, security issues | +| **clippy** | Rust | Idiomatic Rust patterns, performance, correctness | + +Lint results appear as context messages with per-file summaries showing up to 5 issues each, including line numbers and severity levels. + +## Phase 4: Advisory Test Runner + +The `advisory-test-runner.py` script is the final quality gate. It detects your project's test framework, identifies which tests are affected by your changes, and runs only those tests. + +### Supported Test Frameworks + +| Framework | Detection | Targeted Testing | +|-----------|-----------|-----------------| +| **pytest** | `pytest.ini`, `conftest.py`, `pyproject.toml`, `tests/` dir | Maps source files to `test_*.py` counterparts | +| **vitest** | `vitest.config.*` or `test` in `vite.config.*` | Uses `--related` for dependency-graph analysis | +| **jest** | `jest.config.*` or `jest` in `package.json` | Uses `--findRelatedTests` | +| **mocha** | `mocha` in dependencies | Runs full suite | +| **npm test** | `scripts.test` in `package.json` | Runs full suite | +| **go test** | `go.mod` | Maps `.go` files to package directories | +| **cargo test** | `Cargo.toml` | Runs full suite | + +### What Happens When Tests Fail + +When tests pass, you see a brief confirmation message. When tests fail, the hook blocks the Stop with the last 30 lines of test output, giving Claude the information needed to fix the failures before finishing. Tests have a 15-second timeout to keep the feedback loop fast. + +:::caution[Full Suite Triggers] +Editing `conftest.py` in a pytest project triggers a full test suite run rather than targeted tests, since conftest changes can affect any test. The same applies to frameworks without granular test selection (mocha, cargo). +::: + +## Hook Registration + +| Script | Hook | Trigger | Purpose | +|--------|------|---------|---------| +| `collect-edited-files.py` | PostToolUse | Edit, Write | Records which files were modified | +| `syntax-validator.py` | PostToolUse | Edit, Write | Validates JSON/YAML/TOML syntax immediately | +| `format-on-stop.py` | Stop | End of turn | Batch-formats all edited files | +| `lint-file.py` | Stop | End of turn | Batch-lints all edited files | +| `advisory-test-runner.py` | Stop | End of turn | Runs affected tests | + +## Configuration + +The plugin works out of the box with no configuration needed. It automatically detects which tools are available and skips any that aren't installed. To disable specific quality checks, you can modify the plugin's `hooks.json` to remove individual scripts. + +See [Configuration](../customization/configuration/) for details on adjusting plugin settings. + +## Related + +- [Tools Reference](../features/tools/) -- details on each formatting and linting tool +- [Code Intelligence](../features/code-intelligence/) -- AST-based analysis complements lint checks +- [Hooks](../customization/hooks/) -- how advisory and blocking hooks work diff --git a/docs/src/content/docs/plugins/codeforge-lsp.md b/docs/src/content/docs/plugins/codeforge-lsp.md new file mode 100644 index 0000000..fee4590 --- /dev/null +++ b/docs/src/content/docs/plugins/codeforge-lsp.md @@ -0,0 +1,105 @@ +--- +title: CodeForge LSP +description: The CodeForge LSP plugin integrates Language Server Protocol servers for enhanced code intelligence during AI-assisted development. +sidebar: + order: 12 +--- + +The CodeForge LSP plugin gives Claude access to the same code intelligence that powers your IDE -- type checking, go-to-definition, find-references, and more. By connecting Claude to Language Server Protocol servers, it can navigate and understand your codebase with precision rather than relying on text search alone. + +## How It Works + +This is a purely declarative plugin -- it has no hooks and no scripts. It registers LSP server configurations in `plugin.json`, and Claude Code launches each server at startup if its binary is available on PATH. Missing servers are silently skipped, so the plugin never fails on a missing tool. + +When Claude opens a file matching a registered extension, the corresponding LSP server provides rich language features for that file. + +## Registered Servers + +| Server | Command | Languages | File Extensions | +|--------|---------|-----------|-----------------| +| [Pyright](https://github.com/microsoft/pyright) | `pyright-langserver --stdio` | Python | `.py`, `.pyi` | +| [TypeScript Language Server](https://github.com/typescript-language-server/typescript-language-server) | `typescript-language-server --stdio` | TypeScript, JavaScript | `.ts`, `.tsx`, `.js`, `.jsx`, `.mts`, `.cts`, `.mjs`, `.cjs` | +| [gopls](https://pkg.go.dev/golang.org/x/tools/gopls) | `gopls serve` | Go | `.go`, `.mod`, `.sum` | + +Each server maps file extensions to language identifiers. For example, `.tsx` files are identified as `typescriptreact`, while `.js` and `.mjs` files are both identified as `javascript`. + +## Available LSP Operations + +Once a server is running, Claude can use these operations for code navigation and understanding: + +| Operation | Description | Use Case | +|-----------|-------------|----------| +| **goToDefinition** | Jump to where a symbol is defined | Following imports, understanding API contracts | +| **findReferences** | Find every usage of a symbol | Impact analysis before refactoring | +| **hover** | Get type info and documentation | Understanding function signatures and types | +| **documentSymbol** | List all symbols in a file | Getting a structural overview of a module | +| **workspaceSymbol** | Search symbols across the project | Finding classes, functions, or types by name | +| **goToImplementation** | Find implementations of interfaces | Understanding polymorphism and abstractions | +| **prepareCallHierarchy** | Get the call hierarchy at a position | Understanding call chains | +| **incomingCalls** | Find all callers of a function | Understanding who depends on a function | +| **outgoingCalls** | Find all functions called from a position | Understanding a function's dependencies | + +:::tip[LSP vs Text Search] +Text search (Grep) finds string matches. LSP understands your code semantically -- it knows that `User` in an import statement and `User` in a class definition are the same symbol, and it won't confuse them with `UserProfile` or a variable named `user`. This makes refactoring and impact analysis far more reliable. +::: + +## How Agents Use LSP + +Different [agent types](./agent-system/) leverage LSP in different ways: + +- **Read-only agents** (explorer, researcher, architect) use LSP extensively for `goToDefinition`, `findReferences`, and `workspaceSymbol` to understand codebases without modifying files +- **Implementation agents** (generalist, refactorer, migrator) use LSP for navigation during refactoring and to verify that changes don't break references +- **Analysis agents** (security-auditor, dependency-analyst) use `incomingCalls` and `findReferences` to trace data flow and dependency chains + +## Server Activation + +Servers activate only when their binary is found on PATH: + +| Server | Binary | Pre-installed in CodeForge | +|--------|--------|--------------------------| +| Pyright | `pyright-langserver` | Yes (via `npm i -g pyright`) | +| TypeScript LS | `typescript-language-server` | Yes (via `npm i -g typescript-language-server typescript`) | +| gopls | `gopls` | Yes (via `go install golang.org/x/tools/gopls@latest`) | + +If you need LSP for additional languages, you can add server definitions to the plugin's `plugin.json` following the same pattern. + +## Adding More Language Servers + +You can extend the LSP plugin with additional servers by adding entries to the `lspServers` field in `plugin.json`. Each server definition needs three fields: + +```json +{ + "my-server": { + "command": "my-language-server", + "args": ["--stdio"], + "extensionToLanguage": { + ".ext": "language-id" + } + } +} +``` + +The `command` must be the binary name (resolved via PATH). The `args` array is passed to the command. The `extensionToLanguage` map tells Claude Code which files to route to this server. + +:::note[Graceful Degradation] +If a server binary isn't installed, the plugin silently skips it. You can register servers for languages you might use later -- they'll activate automatically when the tool becomes available. +::: + +## Plugin Structure + +Unlike most CodeForge plugins, the LSP plugin contains no scripts or hooks -- just configuration: + +``` +codeforge-lsp/ + .claude-plugin/ + plugin.json -- Plugin metadata + LSP server definitions + README.md +``` + +The `lspServers` field in `plugin.json` is all that's needed. Claude Code reads this at startup and manages server lifecycles automatically. + +## Related + +- [Code Intelligence](../features/code-intelligence/) -- ast-grep and tree-sitter complement LSP +- [Agent System](./agent-system/) -- agents use LSP for code navigation +- [Tools Reference](../features/tools/) -- CLI tools related to code analysis diff --git a/docs/src/content/docs/plugins/dangerous-command-blocker.md b/docs/src/content/docs/plugins/dangerous-command-blocker.md new file mode 100644 index 0000000..164ef09 --- /dev/null +++ b/docs/src/content/docs/plugins/dangerous-command-blocker.md @@ -0,0 +1,112 @@ +--- +title: Dangerous Command Blocker +description: The dangerous command blocker plugin prevents execution of destructive shell commands during Claude Code sessions. +sidebar: + order: 7 +--- + +The dangerous command blocker is your safety net against catastrophic shell commands. It intercepts every Bash command before execution and blocks patterns known to cause irreversible damage -- things like `rm -rf /`, force-pushing to main, or writing to system directories. + +## How It Works + +The plugin registers a PreToolUse hook that fires before every Bash tool call. The `block-dangerous.py` script checks the command against a set of regex patterns. If a match is found, the command is blocked with exit code 2 and a clear explanation of why it was stopped. + +Commands that don't match any dangerous pattern pass through untouched with zero overhead. + +## Blocked Command Categories + +### Destructive File Deletion + +Commands that could wipe out large portions of the filesystem: + +| Pattern | Example | Why It's Blocked | +|---------|---------|-----------------| +| `rm -rf /` | `rm -rf /` | Deletes the entire filesystem | +| `rm -rf ~` | `rm -rf ~/` | Deletes the user's home directory | +| `rm -rf ../` | `rm -rf ../../` | Escapes up the directory tree | +| `sudo rm` | `sudo rm -rf /var/log` | Privileged deletion bypasses permissions | +| `find -exec rm` | `find . -exec rm {} \;` | Recursive deletion via find | +| `find -delete` | `find /tmp -delete` | Bulk deletion via find | + +### Git History Destruction + +Commands that destroy or overwrite git history in ways that are difficult to recover: + +| Pattern | Example | Why It's Blocked | +|---------|---------|-----------------| +| Force push to main/master | `git push --force origin main` | Overwrites shared history | +| Bare force push | `git push -f` | Force push without specifying target | +| Hard reset to remote | `git reset --hard origin/main` | Discards all local work | +| git clean -f | `git clean -fd` | Permanently removes untracked files | + +:::caution[Force Push Safety] +Even `git push -f` without specifying a branch is blocked, because it could unintentionally force-push to the current branch. The blocker requires you to be explicit about what you're doing. +::: + +### System Modification + +Commands that modify critical system directories or create security vulnerabilities: + +| Pattern | Example | Why It's Blocked | +|---------|---------|-----------------| +| `chmod 777` | `chmod 777 app.py` | Creates world-writable files | +| `chmod -R 777` | `chmod -R 777 /var/www` | Recursively weakens permissions | +| Write to system dirs | `> /usr/local/bin/script` | Modifies system binaries | +| Write to `/etc/` | `echo "config" > /etc/hosts` | Modifies system configuration | +| Write to `/bin/` or `/sbin/` | `> /bin/script` | Modifies core system binaries | + +### Disk and Device Operations + +Commands that could destroy disk contents: + +| Pattern | Example | Why It's Blocked | +|---------|---------|-----------------| +| `mkfs.*` | `mkfs.ext4 /dev/sda1` | Formats a disk partition | +| `dd of=/dev/` | `dd if=/dev/zero of=/dev/sda` | Overwrites a device | + +### Container Security + +Commands that could break container isolation: + +| Pattern | Example | Why It's Blocked | +|---------|---------|-----------------| +| `docker run --privileged` | `docker run --privileged ubuntu` | Allows container escape | +| Mount host root | `docker run -v /:/host ubuntu` | Exposes host filesystem | +| Destructive docker ops | `docker rm container_id` | Stops, removes, or kills containers and images (`docker rmi`) | + +## What Happens When a Command Is Blocked + +When the blocker catches a dangerous command, you see a clear message explaining what was blocked and why: + +``` +Blocked: force push to main/master destroys history +``` + +The command never executes. Claude receives the block message and can suggest a safer alternative. + +## Fail-Safe Behavior + +The blocker follows a "fail closed" principle for its own errors: + +- If it can't parse the hook input JSON, it blocks the command (exit code 2) rather than allowing something it couldn't inspect. +- If an unexpected error occurs during pattern matching, it logs the error but allows the command through to avoid blocking legitimate work on a hook bug. + +## Overriding Blocks + +The blocker is designed to catch accidental destructive commands, not to prevent intentional operations. If you genuinely need to run a blocked command, you can use the Claude Code permission prompt to explicitly approve it. The blocker respects user intent -- it's a guardrail, not a cage. + +:::note[Complementary Guards] +This plugin handles command-level safety. For file-path-level protection, see the [Workspace Scope Guard](./workspace-scope-guard/) and [Protected Files Guard](./protected-files-guard/), which cover different attack surfaces. +::: + +## Hook Registration + +| Script | Hook | Matcher | Purpose | +|--------|------|---------|---------| +| `block-dangerous.py` | PreToolUse | Bash | Inspects and blocks dangerous shell commands | + +## Related + +- [Workspace Scope Guard](./workspace-scope-guard/) -- complements command blocking with path enforcement +- [Protected Files Guard](./protected-files-guard/) -- protects specific files from modification +- [Hooks](../customization/hooks/) -- how PreToolUse hooks intercept commands diff --git a/docs/src/content/docs/plugins/frontend-design.md b/docs/src/content/docs/plugins/frontend-design.md new file mode 100644 index 0000000..23e95df --- /dev/null +++ b/docs/src/content/docs/plugins/frontend-design.md @@ -0,0 +1,80 @@ +--- +title: Frontend Design +description: The frontend design plugin provides skills and patterns for frontend development with modern frameworks. +sidebar: + order: 13 +--- + +The frontend design plugin is an official Anthropic plugin that extends Claude's frontend development capabilities. It provides structured guidance for building UI components, applying accessibility standards, and following modern frontend patterns -- making Claude a more effective pair programmer for visual and interactive work. + +## How It Works + +Unlike most CodeForge plugins that use hooks and scripts, this plugin operates as a skill pack. It enriches Claude's knowledge with frontend-specific patterns and best practices that activate when you're working on UI code. The plugin doesn't intercept or modify any operations -- it enhances Claude's ability to generate well-structured frontend code. + +## Capabilities + +### Component Design + +The plugin provides guidance on structuring frontend components following established patterns: + +- **Component composition** -- Breaking UIs into reusable, composable pieces with clear prop interfaces +- **Props design** -- Typing props effectively, using sensible defaults, and designing for flexibility +- **State management** -- Choosing between local state, context, stores, and external state based on scope and complexity +- **Accessibility (a11y)** -- ARIA attributes, keyboard navigation, focus management, screen reader support + +:::tip[Accessibility by Default] +With this plugin active, Claude considers accessibility from the start rather than treating it as an afterthought. This includes semantic HTML, proper heading hierarchy, focus trapping in modals, and ARIA labels for interactive elements. +::: + +### Responsive Design Patterns + +Guidance for building layouts that work across screen sizes: + +- Mobile-first CSS strategies +- Container queries and breakpoint management +- Fluid typography and spacing +- Touch target sizing and interaction patterns + +### Design System Integration + +Patterns for working with design systems and component libraries: + +- **Token-based styling** -- Using design tokens for colors, spacing, typography, and other values instead of hardcoded CSS +- **Component variants** -- Structuring component APIs with variant props (size, color, emphasis) that map to design system tokens +- **Theme customization** -- Supporting light/dark modes and custom themes through CSS custom properties or framework-specific theming + +## Framework Support + +The plugin provides general component architecture applicable across frameworks, and complements framework-specific skills available in the [Skill Engine](./skill-engine/): + +| Framework | Skill Coverage | +|-----------|---------------| +| **Svelte 5** | Runes, reactivity, component patterns (via Skill Engine) | +| **React** | General component patterns and hooks | +| **Vue** | Composition API patterns | +| **General** | Framework-agnostic architecture, HTML/CSS best practices | + +### Example Use Cases + +Here are some examples of tasks where the frontend design plugin improves Claude's output: + +- **"Build a responsive data table component with sorting and pagination"** -- Claude applies proper ARIA roles for tables, keyboard-navigable sort controls, and responsive overflow handling +- **"Create an accessible modal dialog with focus trapping"** -- Claude includes focus trap logic, escape key handling, proper ARIA attributes, and scroll lock on the body +- **"Design a form component with validation and error states"** -- Claude generates accessible error messages linked to inputs via `aria-describedby`, live region announcements, and proper form semantics +- **"Set up a theme switcher with CSS custom properties"** -- Claude structures tokens hierarchically, respects `prefers-color-scheme`, and persists the preference + +## When the Plugin Activates + +The frontend design plugin activates whenever Claude is working on frontend code -- HTML, CSS, JavaScript/TypeScript components, or UI-related configuration. You don't need to explicitly invoke it. The plugin's patterns influence code generation, component structure suggestions, and the architectural advice Claude provides. + +It works particularly well when combined with the [Skill Engine's](./skill-engine/) framework-specific skills. For example, asking Claude to build a Svelte 5 component benefits from both this plugin's general UI patterns and the Svelte 5 skill's runes-based reactivity knowledge. + +## Official Plugin + +This plugin is maintained by Anthropic and distributed as part of the Claude Code ecosystem. It receives updates alongside Claude Code itself and is designed to work with Claude's built-in understanding of frontend development. + +## Related + +- [Skill Engine](./skill-engine/) -- framework-specific skills (Svelte 5, etc.) +- [Skills Reference](../features/skills/) -- all available skills +- [Agent System](./agent-system/) -- agents that handle frontend tasks diff --git a/docs/src/content/docs/plugins/index.md b/docs/src/content/docs/plugins/index.md new file mode 100644 index 0000000..e49a352 --- /dev/null +++ b/docs/src/content/docs/plugins/index.md @@ -0,0 +1,180 @@ +--- +title: Plugins +description: Overview of the CodeForge plugin system — how plugins work, what they provide, and how to enable or disable them. +sidebar: + order: 1 +--- + +CodeForge extends Claude Code through a modular plugin system. Each plugin bundles related hooks, scripts, agents, skills, or commands into a self-contained package that integrates directly into your development workflow. You get intelligent task delegation, domain-specific knowledge, specification management, and safety guardrails — all without manual configuration. + +## What Plugins Do For You + +Plugins are the backbone of CodeForge's power. Instead of configuring Claude Code from scratch, you get a curated set of capabilities that work together out of the box: + +- **Agents** delegate tasks to specialists with the right tools and constraints for the job +- **Skills** inject domain expertise (frameworks, patterns, workflows) into your session automatically +- **Hooks** run scripts at key moments — before a tool executes, after it completes, or when a turn finishes +- **Safety guards** prevent destructive commands, enforce file boundaries, and protect critical configuration + +Every plugin is independent. You can enable or disable any plugin without affecting the others. + +## How Plugins Work + +Plugins live inside `.devcontainer/plugins/` and follow a standard directory structure. Each plugin declares its capabilities in a `.claude-plugin/plugin.json` manifest that tells CodeForge what the plugin provides and how to activate it. + +### Plugin Structure + +A typical plugin directory looks like this: + +``` +plugins/ +└── my-plugin/ + ├── .claude-plugin/ + │ └── plugin.json # Manifest: name, description, author + ├── hooks/ + │ └── hooks.json # Hook registrations (which events to listen for) + ├── scripts/ # Python scripts that hooks execute + ├── agents/ # Agent definitions as Markdown files (optional) + └── skills/ # Skill packs as SKILL.md files (optional) +``` + +The `plugin.json` manifest is minimal — it identifies the plugin and its author: + +```json +{ + "name": "agent-system", + "description": "17 custom agents with built-in agent redirection, CWD injection, and read-only bash enforcement", + "author": { + "name": "AnExiledDev" + } +} +``` + +The real configuration lives in `hooks.json`, which maps hook events to the scripts that handle them. Here is an example from the skill engine: + +```json +{ + "hooks": { + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/skill-suggester.py", + "timeout": 3 + } + ] + } + ] + } +} +``` + +Each hook registration specifies the event to listen for, the script to run, and a timeout in seconds. The `${CLAUDE_PLUGIN_ROOT}` variable resolves to the plugin's directory, so scripts are always found regardless of installation path. + +### The Hook System + +Hooks are the primary integration mechanism. They let plugins run custom logic at specific moments during a Claude Code session. Each hook fires at a defined point in the tool lifecycle: + +| Hook Event | When It Fires | Typical Use | +|------------|---------------|-------------| +| **PreToolUse** | Before a tool executes | Block dangerous commands, enforce read-only mode, redirect agents | +| **PostToolUse** | After a tool completes | Inject context, check for regressions, process results | +| **Stop** | When the assistant finishes a turn | Run quality checks, send notifications, remind about specs | +| **UserPromptSubmit** | When the user sends a prompt | Auto-suggest skills, fetch ticket context, inject state | +| **SubagentStart** | When a subagent is spawned | Inject working directory, configure agent environment | +| **TeammateIdle** | When a teammate agent is idle | Check for task completion, reassign work | +| **TaskCompleted** | When a team task finishes | Verify results, trigger follow-up work | + +Hook scripts are Python programs that receive JSON on stdin and return JSON on stdout. They can either **allow** the operation (exit 0), **block** it (exit 2 with a reason), or **inject context** (return additional information for Claude to use). + +:::tip[Hooks Are Non-Destructive] +Most hooks are advisory — they add context or surface reminders without interrupting your flow. Only safety-critical hooks (like the dangerous command blocker) actively block operations. +::: + +See [Hooks](../customization/hooks/) for the full hook API and configuration details. + +## Installed Plugins + +CodeForge ships with 11 local marketplace plugins plus 1 external Anthropic plugin, organized into two categories: **core plugins** that provide primary functionality, and **safety and integration plugins** that protect your work and connect to external tools. + +### Core Plugins + +These plugins deliver the headline features of CodeForge — intelligent delegation, domain expertise, and workflow management. + +| Plugin | What It Does | +|--------|-------------| +| [Agent System](./agent-system/) | 17 specialized agents with automatic delegation, CWD injection, and read-only enforcement | +| [Skill Engine](./skill-engine/) | 21 domain skills with context-aware auto-suggestion | +| [Spec Workflow](./spec-workflow/) | Full specification lifecycle from creation through implementation to as-built closure | +| [Ticket Workflow](./ticket-workflow/) | GitHub issue integration with EARS-formatted tickets and automated PR reviews | + +### Safety Plugins + +These plugins prevent mistakes, enforce boundaries, and keep your work safe. + +| Plugin | What It Does | +|--------|-------------| +| [Auto Code Quality](./auto-code-quality/) | Automated formatting, linting, and advisory test running | +| [Dangerous Command Blocker](./dangerous-command-blocker/) | Blocks destructive shell commands like `rm -rf`, `drop table`, force pushes | +| [Workspace Scope Guard](./workspace-scope-guard/) | Ensures file operations stay within your project directory | +| [Protected Files Guard](./protected-files-guard/) | Prevents modification of secrets, lock files, and critical configuration | + +### Integration Plugins + +These plugins connect CodeForge to external tools and add quality-of-life features. + +| Plugin | What It Does | +|--------|-------------| +| [Session Context](./session-context/) | Injects git state, harvests TODOs, and reminds about uncommitted work | +| [Notify Hook](./notify-hook/) | Desktop notifications when tasks complete | +| [CodeForge LSP](./codeforge-lsp/) | Language server protocol integration for Python, TypeScript, and Go | +| [Frontend Design](./frontend-design/) | Frontend design patterns and UI component skills (external Anthropic plugin) | + +## Enabling and Disabling Plugins + +Plugins are declared in `settings.json` under the `enabledPlugins` key. Every plugin listed there activates automatically when your container starts. + +```json +{ + "enabledPlugins": [ + "agent-system", + "skill-engine", + "spec-workflow", + "session-context", + "auto-code-quality", + "workspace-scope-guard", + "dangerous-command-blocker", + "protected-files-guard", + "codeforge-lsp", + "ticket-workflow", + "notify-hook", + "frontend-design" + ] +} +``` + +To disable a plugin, remove it from the list. To re-enable it, add it back. Changes take effect on the next container start. + +:::caution[Safety Plugins] +Think carefully before disabling safety plugins like `dangerous-command-blocker` or `workspace-scope-guard`. These protect against accidental data loss and scope violations. +::: + +See [Configuration](../customization/configuration/) for the full `settings.json` reference. + +## The Plugin Marketplace + +All plugins ship through the CodeForge devs-marketplace — a curated collection bundled with the devcontainer. The marketplace lives at `.devcontainer/plugins/devs-marketplace/plugins/` and contains every plugin's source code, hooks, agents, skills, and scripts. + +The marketplace model means plugins are tested and maintained alongside CodeForge itself. When you update your devcontainer, you get the latest versions of all plugins automatically. + +:::note[Custom Plugins] +The plugin structure is open and well-defined. You can create your own plugins by following the same directory layout and manifest format. Place custom plugins in `.devcontainer/plugins/` and add them to `enabledPlugins` in your settings. +::: + +## Related + +- [Hooks](../customization/hooks/) — detailed hook API and event documentation +- [Configuration](../customization/configuration/) — managing settings and plugin activation +- [Agent System](./agent-system/) — the flagship plugin for intelligent delegation +- [Architecture](../reference/architecture/) — how plugins fit into the CodeForge system diff --git a/docs/src/content/docs/plugins/notify-hook.md b/docs/src/content/docs/plugins/notify-hook.md new file mode 100644 index 0000000..4c9b00a --- /dev/null +++ b/docs/src/content/docs/plugins/notify-hook.md @@ -0,0 +1,82 @@ +--- +title: Notify Hook +description: The notify hook plugin sends desktop notifications when Claude Code completes tasks or needs attention. +sidebar: + order: 11 +--- + +The notify hook plugin sends a desktop notification every time Claude finishes a turn. This is especially useful during long-running tasks -- you can switch to another window or grab a coffee and get alerted the moment Claude needs your attention again. + +## How It Works + +The plugin registers a single Stop hook that calls the `claude-notify` command whenever Claude completes a response. The notification fires regardless of what Claude was doing, so you always know when it's your turn. + +```json +{ + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "claude-notify", + "timeout": 5 + } + ] + } + ] + } +} +``` + +The `claude-notify` command is a lightweight wrapper provided by CodeForge that handles platform-specific notification delivery. It has a 5-second timeout to ensure it never delays the session. + +## When Notifications Fire + +Notifications are sent at the end of every assistant turn: + +- Claude finishes implementing a feature or fixing a bug +- Claude completes a code review or analysis +- Claude encounters an error and needs your guidance +- Claude asks a clarifying question before proceeding +- A long build, test, or deployment step completes +- Claude finishes a multi-step refactoring operation + +:::tip[Pair It with Context] +Notifications work especially well alongside the [Session Context](./session-context/) plugin. When you return to Claude after a notification, the session context ensures Claude already has current git state and change summaries ready. +::: + +## Why Notifications Matter + +During AI-assisted development, many tasks take longer than you'd want to sit and watch. Test suites, dependency installations, complex refactoring across multiple files -- these operations can take minutes. Without notifications, you're stuck polling the terminal or missing the moment Claude finishes. + +The notify hook solves this by turning Claude Code into an asynchronous workflow. You ask Claude to do something, switch to documentation, email, or another task, and get pinged when it's done. This is especially valuable when running multiple Claude sessions in parallel across different projects. + +## Interaction with Other Stop Hooks + +The notify hook fires alongside other Stop hooks like the [commit reminder](./session-context/) and [advisory test runner](./auto-code-quality/). All Stop hooks run in the order they're registered. The notification fires even if another Stop hook blocks -- so you'll still get alerted when Claude needs your attention due to test failures or uncommitted changes. + +## Platform Support + +Desktop notifications are delivered from the DevContainer to your host system. How they appear depends on your setup: + +| Environment | Behavior | +|-------------|----------| +| **VS Code + DevContainer** | Notifications forward through VS Code's notification system | +| **Terminal-based sessions** | Uses the terminal's bell or notification capability | +| **Remote/SSH sessions** | Notifications may not reach the host depending on forwarding setup | + +:::note[Notification Forwarding] +If notifications aren't appearing, check that your terminal or editor supports notification forwarding from containers. Some terminal emulators require explicit configuration to display notifications from remote sessions. +::: + +## Hook Registration + +| Script | Hook | Purpose | +|--------|------|---------| +| `claude-notify` | Stop | Sends desktop notification when assistant turn completes | + +## Related + +- [Session Context](./session-context/) -- provides the context that's available when you return after a notification +- [Hooks](../customization/hooks/) -- how Stop hooks trigger notifications diff --git a/docs/src/content/docs/plugins/protected-files-guard.md b/docs/src/content/docs/plugins/protected-files-guard.md new file mode 100644 index 0000000..98940c7 --- /dev/null +++ b/docs/src/content/docs/plugins/protected-files-guard.md @@ -0,0 +1,115 @@ +--- +title: Protected Files Guard +description: The protected files guard plugin prevents modification of designated critical files during Claude Code sessions. +sidebar: + order: 9 +--- + +The protected files guard prevents Claude from modifying files that should never be touched by an AI assistant -- secrets, credentials, lock files, and other sensitive content. Even if Claude has a legitimate reason to suggest changes to these files, the guard ensures that only a human makes those edits. + +## How It Works + +The plugin operates through two protection layers that together cover all modification paths: + +| Script | What It Intercepts | +|--------|-------------------| +| `guard-protected.py` | Write and Edit tool calls targeting protected files | +| `guard-protected-bash.py` | Bash commands that would write to protected files (via redirects, `tee`, `cp`, `mv`, `sed -i`, etc.) | + +Both scripts use the same set of protected file patterns. When a match is found, the operation is blocked with exit code 2 and a message explaining why the file is protected and what to do instead. + +## Protected File Categories + +### Secrets and Environment Variables + +Files that typically contain API keys, database passwords, and other credentials: + +| Pattern | Examples | +|---------|---------| +| `.env` | `.env`, `config/.env` | +| `.env.*` | `.env.local`, `.env.production` | +| `credentials.json` | `credentials.json`, `config/credentials.json` | +| `secrets.yaml` / `secrets.yml` / `secrets.json` | Any secrets file | +| `.secrets` | `.secrets` | + +### Lock Files + +Lock files should only be modified by their respective package managers, never edited directly: + +| Pattern | Correct Alternative | +|---------|-------------------| +| `package-lock.json` | Run `npm install` instead | +| `yarn.lock` | Run `yarn install` instead | +| `pnpm-lock.yaml` | Run `pnpm install` instead | +| `Gemfile.lock` | Run `bundle install` instead | +| `poetry.lock` | Run `poetry install` instead | +| `Cargo.lock` | Run `cargo build` instead | +| `composer.lock` | Run `composer install` instead | +| `uv.lock` | Run `uv sync` instead | + +:::tip[Lock File Edits] +The guard's block messages include the correct command to use. For example, blocking a `package-lock.json` edit tells you to run `npm install` instead. This helps Claude suggest the right approach. +::: + +### Cryptographic Material + +Private keys, certificates, and other sensitive cryptographic files: + +| Pattern | What It Protects | +|---------|-----------------| +| `*.pem` | PEM-encoded keys and certificates | +| `*.key` | Private key files | +| `*.crt` | Certificate files | +| `*.p12` / `*.pfx` | PKCS#12 certificate bundles | +| `id_rsa*`, `id_ed25519*`, `id_ecdsa*` | SSH private keys | + +### Authentication Configuration + +Directories and files containing authentication tokens and credentials: + +| Pattern | What It Protects | +|---------|-----------------| +| `.ssh/` | SSH keys and configuration | +| `.aws/` | AWS credentials and config | +| `.netrc` | Network authentication credentials | +| `.npmrc` | npm registry auth tokens | +| `.pypirc` | PyPI upload credentials | + +### Git Internals + +| Pattern | What It Protects | +|---------|-----------------| +| `.git/` | Git internal state -- always managed by git itself | + +## The Bash Protection Layer + +The `guard-protected-bash.py` script adds a second layer of protection specifically for shell commands. It detects write operations by looking for these patterns in the command string: + +- **Output redirection**: `> file` and `>> file` +- **tee**: `tee file` and `tee -a file` +- **File operations**: `cp ... dest` and `mv ... dest` +- **In-place edits**: `sed -i ... file` +- **Heredoc writes**: `cat > file` + +For each detected write target, the script checks it against the same protected patterns used by the Edit/Write guard. If a match is found, the entire command is blocked. + +:::caution[Bash Layer Limitations] +The Bash guard uses regex pattern matching on command strings, which covers common write patterns but can't catch every possible way a shell command might modify a file. The Edit/Write guard is the primary protection layer; the Bash guard adds defense in depth. +::: + +## Fail-Safe Behavior + +Both guard scripts follow a "fail closed" philosophy for JSON parsing errors -- if the hook can't read its input, it blocks the operation rather than allowing something it couldn't inspect. For other unexpected errors, the scripts log to stderr and allow the operation to prevent false blocks from breaking the workflow. + +## Hook Registration + +| Script | Hook | Matcher | Purpose | +|--------|------|---------|---------| +| `guard-protected.py` | PreToolUse | Edit, Write | Blocks Write/Edit on protected files | +| `guard-protected-bash.py` | PreToolUse | Bash | Blocks shell commands that write to protected files | + +## Related + +- [Workspace Scope Guard](./workspace-scope-guard/) -- directory-level access control +- [Dangerous Command Blocker](./dangerous-command-blocker/) -- command-level safety +- [Hooks](../customization/hooks/) -- how PreToolUse hooks work diff --git a/docs/src/content/docs/plugins/session-context.md b/docs/src/content/docs/plugins/session-context.md new file mode 100644 index 0000000..9171a89 --- /dev/null +++ b/docs/src/content/docs/plugins/session-context.md @@ -0,0 +1,137 @@ +--- +title: Session Context +description: The session context plugin injects useful runtime information — git state, TODOs, and commit reminders — into Claude Code sessions. +sidebar: + order: 10 +--- + +The session context plugin gives Claude a running awareness of your project's state. At session start, it injects the current git branch, working tree status, and any TODO items in your codebase. At the end of each turn, it reminds about uncommitted changes. This context helps Claude make better decisions without you having to repeat project state manually. + +## How It Works + +The plugin registers hooks at two lifecycle points: + +| Hook Point | What Fires | Purpose | +|-----------|------------|---------| +| **SessionStart** | Git state injector + TODO harvester | Gives Claude full project awareness at the start of every session | +| **Stop** | Commit reminder | Prompts about uncommitted changes before the turn ends | + +The SessionStart scripts (git state injector and TODO harvester) are purely advisory -- they inject context without making decisions. The commit reminder is different: it uses a "block" decision to keep Claude from finishing a turn when there are uncommitted changes. + +## Git State Injection + +The `git-state-injector.py` script runs at the beginning of every session and provides Claude with a snapshot of your repository: + +### What Gets Injected + +- **Working directory** -- The full path, with a reminder to restrict operations to this directory +- **Current branch** -- Branch name or detached HEAD indicator +- **Working tree status** -- Counts of modified, added, deleted, and untracked files, plus the short status output +- **Recent commits** -- The last 5 commits (one-line format) +- **Uncommitted diff stats** -- Summary of what's changed but not yet committed + +### Example Output + +Here's what Claude sees at the start of a session: + +``` +[Git State] +Working Directory: /workspaces/projects/MyAPI -- restrict all file +operations to this directory unless explicitly instructed otherwise. +Branch: feature/auth-refactor +Status: 3 modified, 1 untracked + M src/auth/login.py + M src/auth/tokens.py + M tests/test_login.py +?? src/auth/oauth.py +Recent commits: +a1b2c3d Add token refresh endpoint +d4e5f6g Fix login rate limiting +7h8i9j0 Update auth middleware tests +Uncommitted changes: + src/auth/login.py | 12 ++++++------ + src/auth/tokens.py | 8 ++++---- + 2 files changed, 10 insertions(+), 10 deletions(-) +``` + +:::tip[Why This Matters] +Without git state injection, Claude starts every session blind. It doesn't know what branch you're on, what files have changed, or what you've been working on. This context lets Claude make appropriate git operations, avoid conflicts, and understand the current state of work. +::: + +### Safety Caps + +The injector is careful not to bloat Claude's context: + +| Limit | Value | +|-------|-------| +| Status lines | 20 lines max | +| Diff stat lines | 15 lines max | +| Total output | 2000 characters max | + +### Non-Git Projects + +If the working directory isn't a git repository, the injector still fires -- it injects just the working directory path with the scope restriction reminder. + +## TODO Harvester + +The `todo-harvester.py` script scans your codebase for tech debt markers at session start. It uses grep to find TODO, FIXME, HACK, and XXX comments across source files and surfaces a summary. + +### Scanned File Types + +The harvester searches across common source file types: + +`.py`, `.ts`, `.tsx`, `.js`, `.jsx`, `.go`, `.rs`, `.sh`, `.svelte`, `.vue`, `.rb`, `.java`, `.kt` + +### Excluded Directories + +Build artifacts and dependencies are automatically excluded: + +`node_modules`, `.git`, `__pycache__`, `.venv`, `venv`, `dist`, `build`, `vendor`, `.next`, `.nuxt`, `target`, `.mypy_cache`, `.pytest_cache` + +### Example Output + +``` +[Tech Debt] 7 TODO/FIXME items found across 4 files +Top items: + src/auth/login.py:42: # TODO: Add rate limiting per IP + src/auth/tokens.py:15: # FIXME: Token expiry not checked + src/api/routes.py:88: # TODO: Validate pagination params + tests/test_auth.py:3: # HACK: Mock needs cleanup +``` + +The harvester shows up to 10 items with relative file paths and line numbers, capped at 800 characters total. + +## Commit Reminder + +The `commit-reminder.py` script fires at the Stop hook when Claude finishes a turn. It checks for uncommitted changes and, if any exist, blocks the stop with a summary so Claude can suggest committing. + +### What It Reports + +The reminder counts staged and unstaged changes separately: + +``` +[Uncommitted Changes] 5 files with changes (2 staged, 3 unstaged). +Consider asking the user if they'd like to commit before finishing. +``` + +### Loop Prevention + +The commit reminder uses the `stop_hook_active` guard to prevent infinite loops. If another Stop hook has already blocked (like the advisory test runner), the commit reminder skips itself rather than stacking blocks. + +:::note[Advisory, Not Mandatory] +The commit reminder blocks the Stop to give Claude a chance to mention uncommitted changes, but it doesn't force a commit. Claude will typically ask if you'd like to commit -- you can say no and continue. +::: + +## Hook Registration + +| Script | Hook | Purpose | +|--------|------|---------| +| `git-state-injector.py` | SessionStart | Injects git branch, status, and recent commits | +| `todo-harvester.py` | SessionStart | Surfaces TODO/FIXME/HACK/XXX comment counts | +| `commit-reminder.py` | Stop | Reminds about uncommitted changes at turn boundaries | + +## Related + +- [Notify Hook](./notify-hook/) -- desktop notifications complement session context +- [Agent System](./agent-system/) -- agents receive session context through these hooks +- [Hooks](../customization/hooks/) -- how SessionStart and Stop hooks work diff --git a/docs/src/content/docs/plugins/skill-engine.md b/docs/src/content/docs/plugins/skill-engine.md new file mode 100644 index 0000000..a4ff6c7 --- /dev/null +++ b/docs/src/content/docs/plugins/skill-engine.md @@ -0,0 +1,182 @@ +--- +title: Skill Engine +description: The skill engine plugin provides 21 domain-specific knowledge packs with automatic suggestion based on conversation context. +sidebar: + order: 3 +--- + +The skill engine delivers domain-specific expertise into your Claude Code sessions through curated knowledge packs called skills. Each skill is a focused Markdown document that teaches Claude how to work with a specific framework, tool, pattern, or workflow. Skills activate automatically when the conversation context matches, or you can invoke them manually with slash commands. + +Think of skills as expert consultants that join your session exactly when their knowledge is needed. Working with FastAPI? The FastAPI skill loads automatically, bringing patterns for routing, dependency injection, SSE streaming, and Pydantic v2 models. Writing tests? The testing skill surfaces with pytest fixtures, Vitest patterns, and test quality principles. + +## How Auto-Suggestion Works + +The skill engine includes a `skill-suggester.py` hook that analyzes every prompt you submit. It fires on the `UserPromptSubmit` event — meaning it runs before Claude processes your message. The suggester matches your prompt against two types of patterns for each skill: + +- **Phrases** — natural language patterns like "build a fastapi app", "write tests", "refactor this", "debug logs" +- **Terms** — specific technical keywords like "pytest", "uvicorn", "pydantic", "ast-grep" + +When your prompt matches one or more skills, the hook injects an activation directive into Claude's context. Claude then evaluates each matched skill for relevance to your actual request and loads the ones that apply. + +:::tip[Auto-Suggestion Is Smart, Not Greedy] +The suggester matches broadly but Claude filters for relevance. If you mention "pytest" while discussing something unrelated to testing, the testing skill might match on the keyword but Claude will skip loading it if it is not relevant to your actual question. +::: + +### How Skills Inject Context + +Each skill is a `SKILL.md` file containing structured knowledge — mental models, code patterns, configuration guidance, ambiguity policies, and reference links. When a skill activates, its full content is loaded into Claude's context window. This gives Claude deep, authoritative knowledge about that specific domain for the duration of the task. + +Skills are designed to be practical, not encyclopedic. A typical skill includes: + +- **Mental model** — how to think about the domain (2-3 paragraphs) +- **Core patterns** — annotated code examples for the most common tasks +- **Decision guidance** — what to do when the user does not specify a preference (ambiguity policy) +- **Reference files** — links to deeper reference documents for advanced topics + +## Available Skills + +CodeForge ships with 21 skills organized into three categories. + +### Frameworks and Libraries + +Domain expertise for popular frameworks and tools. These skills cover API design, data modeling, and implementation patterns. + +| Skill | What It Teaches | +|-------|----------------| +| **fastapi** | REST APIs, Pydantic v2 models, SSE streaming, dependency injection, ASGI middleware | +| **svelte5** | Svelte 5 runes, SvelteKit routing, component reactivity, state management | +| **pydantic-ai** | PydanticAI agent framework, tool definitions, streaming, model fallbacks | +| **docker** | Dockerfile best practices, multi-stage builds, Docker Compose, health checks | +| **docker-py** | Python Docker SDK, container management, log streaming, health monitoring | +| **sqlite** | SQLite patterns, WAL mode, FTS5 full-text search, CTEs, window functions | + +### Development Practices + +Process and methodology skills that improve code quality, security, and maintainability. + +| Skill | What It Teaches | +|-------|----------------| +| **testing** | Test writing patterns for pytest, Vitest, Jest; fixtures, mocking, FIRST principles | +| **debugging** | Systematic debugging approaches, log analysis, container diagnostics | +| **refactoring-patterns** | Safe refactoring techniques, code smell identification, extract/inline patterns | +| **security-checklist** | Security audit checklists, OWASP guidance, vulnerability scanning | +| **api-design** | REST API conventions, versioning, pagination, error responses, OpenAPI docs | +| **documentation-patterns** | Documentation standards, docstrings, JSDoc, architecture docs | +| **performance-profiling** | Profiling with cProfile, py-spy, scalene; flamegraphs, benchmarking | +| **dependency-management** | Dependency auditing, outdated packages, vulnerability scanning, license checks | +| **migration-patterns** | Framework migration strategies, version upgrades, CommonJS to ESM | + +### Claude Code and CodeForge + +Skills for working with Claude Code itself and extending CodeForge. + +| Skill | What It Teaches | +|-------|----------------| +| **claude-code-headless** | Running Claude Code in CI/CD pipelines, stream-json output, headless permissions | +| **claude-agent-sdk** | Claude Agent SDK usage, MCP tools, subagent definitions, SDK hooks | +| **skill-building** | How to create new skills for the skill engine | +| **git-forensics** | Git history analysis, blame, bisect, pickaxe search, reflog recovery | +| **ast-grep-patterns** | AST-grep pattern writing for syntax-aware code search | +| **team** | Multi-agent team coordination, task decomposition, parallel workstreams | + +:::note[Cross-Plugin Skills] +The `specification-writing` skill and the spec lifecycle skills (`spec-new`, `spec-build`, etc.) live in the [Spec Workflow](./spec-workflow/) plugin, not the skill engine. However, the skill-suggester registers keywords for them so they are auto-suggested alongside skill-engine skills. +::: + +## Skill Activation Patterns + +Here is a sampling of the phrases and terms that trigger each category of skill, so you know what to expect: + +| When You Say... | Skills That Activate | +|-----------------|---------------------| +| "Build a FastAPI app" | fastapi | +| "Write tests for this module" | testing | +| "Refactor this function" | refactoring-patterns | +| "Check for security vulnerabilities" | security-checklist | +| "Profile this code" or "find the bottleneck" | performance-profiling | +| "Create a spec for this feature" | spec-new | +| "Build from the spec" | spec-build | +| "Debug the logs" or "what went wrong" | debugging | +| "Spawn a team" or "work in parallel" | team | +| "Search with ast-grep" | ast-grep-patterns | + +## Skills and Agents + +Skills and agents are complementary. Agents define *who* does the work (with what tools and constraints), while skills define *what knowledge* they bring. + +Many agents come pre-loaded with relevant skills through their frontmatter configuration. For example: + +- The **architect** agent loads `api-design` and spec lifecycle skills +- The **test-writer** agent loads the `testing` skill +- The **refactorer** agent loads `refactoring-patterns` +- The **security-auditor** agent loads `security-checklist` +- The **explorer** agent loads `ast-grep-patterns` + +This means when the agent system delegates to a specialist, that specialist already has the domain knowledge it needs. The skill engine's auto-suggestion layer adds a second pathway — skills can also activate based on your prompt, even when no agent delegation occurs. + +## Creating Custom Skills + +You can create your own skills by adding a `SKILL.md` file to the skill engine's `skills/` directory. The built-in **skill-building** skill teaches you exactly how to do this — just ask Claude to "build a skill" or "create a skill" and it will activate. + +A skill file follows this structure: + +```markdown +--- +name: my-custom-skill +description: >- + What this skill teaches, when to use it, and when not to use it. +version: 0.1.0 +--- + +# Skill Title + +## Mental Model +[How to think about this domain — 2-3 paragraphs] + +## Core Patterns +[Annotated code examples for common tasks] + +## Ambiguity Policy +[Default choices when the user doesn't specify preferences] + +## Reference Files +[Links to deeper reference documents] +``` + +The `description` field in the frontmatter is important — it tells the system (and other developers) when this skill should activate and when it should not. Be specific about both use cases and anti-patterns. + +:::note[Keyword Registration] +For your custom skill to participate in auto-suggestion, you need to add its phrases and terms to the `skill-suggester.py` script's `SKILLS` dictionary. Without this registration, the skill can still be activated manually but will not be auto-suggested. +::: + +## Configuration + +The skill engine is configured through its plugin manifest at `.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json`. The hook registration in `hooks/hooks.json` controls when the suggester fires. + +Skill files live in the `skills/` directory, with each skill in its own subfolder containing a `SKILL.md` and optionally a `references/` directory for supplementary documentation. + +``` +skill-engine/ +├── .claude-plugin/ +│ └── plugin.json +├── hooks/ +│ └── hooks.json # UserPromptSubmit → skill-suggester.py +├── scripts/ +│ └── skill-suggester.py # Phrase/term matching logic +└── skills/ + ├── fastapi/ + │ ├── SKILL.md + │ └── references/ # Deep-dive docs on routing, SSE, etc. + ├── testing/ + │ └── SKILL.md + ├── debugging/ + │ └── SKILL.md + └── ... # 21 skills total +``` + +## Related + +- [Skills Reference](../features/skills/) — detailed per-skill documentation +- [Agent System](./agent-system/) — agents that carry pre-loaded skills +- [Spec Workflow](./spec-workflow/) — the specification-writing skill powers spec authoring +- [Hooks](../customization/hooks/) — how the skill suggester hook integrates diff --git a/docs/src/content/docs/plugins/spec-workflow.md b/docs/src/content/docs/plugins/spec-workflow.md new file mode 100644 index 0000000..c9c901d --- /dev/null +++ b/docs/src/content/docs/plugins/spec-workflow.md @@ -0,0 +1,224 @@ +--- +title: Spec Workflow +description: The specification workflow plugin manages the full lifecycle of feature specifications — from creation through implementation to as-built closure. +sidebar: + order: 4 +--- + +The spec workflow plugin enforces a specification-driven development process. Every non-trivial feature gets a spec before implementation begins, and every implementation ends with an as-built spec update that documents what was actually built. This creates a reliable loop: plan the work, do the work, record what happened. + +Why does this matter? Specs force you to think through edge cases, acceptance criteria, and scope boundaries while changes are cheap — before any code exists. The as-built closure step catches drift between what was planned and what was delivered. Together, they give you a living record of every feature in your project. + +## The Specification Lifecycle + +The spec workflow follows a clear seven-stage lifecycle. Each stage has a dedicated slash command, and each stage feeds into the next: + +``` +/spec-init --> /spec-new --> /spec-refine --> /spec-build --> /spec-review --> /spec-update + | | | | | | +Bootstrap Create a Validate Implement Verify code Close the +.specs/ draft spec assumptions the feature vs. spec loop + + /spec-check (audit health — runs independently) +``` + +### Stage 1: Initialize (`/spec-init`) + +Bootstrap the `.specs/` directory at your project root. This creates the directory structure, `MILESTONES.md` for tracking releases, and `BACKLOG.md` for capturing deferred work. You only run this once per project. + +### Stage 2: Create (`/spec-new`) + +Create a new feature specification from the standard template. The command infers a domain folder from the feature name (e.g., `auth/`, `search/`, `api/`) and generates a structured Markdown file with sections for intent, acceptance criteria, requirements, dependencies, and scope boundaries. + +New specs always start with: +- **Status:** `planned` +- **Approval:** `draft` +- All requirements tagged `[assumed]` + +This is intentional. Draft specs contain unvalidated assumptions — they should not be implemented until those assumptions are confirmed. + +### Stage 3: Refine (`/spec-refine`) + +Walk through every `[assumed]` requirement with the user, validating tech decisions and scope boundaries. As each requirement is confirmed, it upgrades from `[assumed]` to `[user-approved]`. The spec's approval status changes to `user-approved` only after all requirements pass review. + +:::caution[Do Not Skip Refinement] +The `/spec-build` command enforces a hard gate: it refuses to implement any spec that is not `user-approved`. Building against draft specs with unvalidated assumptions risks wasted work. Always refine first. +::: + +### Stage 4: Build (`/spec-build`) + +The most powerful command in the workflow. It orchestrates the full implementation lifecycle in five phases: + +1. **Discovery and Gate Check** — reads the spec, verifies approval status, builds context from key files +2. **Implementation Planning** — creates a structured plan mapping requirements to file changes, enters plan mode for user approval +3. **Implementation** — executes the plan step by step, flipping acceptance criteria from `[ ]` to `[~]` as each is addressed +4. **Comprehensive Review** — audits every requirement, verifies acceptance criteria with tests, checks code quality and spec consistency +5. **Spec Closure** — updates status, adds implementation notes, documents discrepancies + +Because Phase 5 performs full as-built closure, you do not need a separate `/spec-update` run after using `/spec-build`. + +:::tip[Team Spawning for Complex Specs] +When a spec has 8+ requirements or spans multiple layers (backend, frontend, tests), `/spec-build` automatically recommends spawning a team of specialist agents. A researcher explores patterns, a test-writer creates tests in a worktree, and a doc-writer updates documentation — all working in parallel. +::: + +### Stage 5: Review (`/spec-review`) + +Standalone implementation verification. Use this after manual implementation, for post-change regression checks, or during pre-release audits. It reads the code, verifies every requirement and acceptance criterion against the implementation, and recommends `/spec-update` when done. + +### Stage 6: Update (`/spec-update`) + +Close the as-built loop. Updates the spec to reflect what was actually built — sets status, checks off acceptance criteria, adds implementation notes for deviations, and updates file paths. Use this after manual implementation or when the spec-reminder hook nudges you. + +### Stage 7: Check (`/spec-check`) + +Audit spec health across the project. Run this before starting a new milestone to ensure all specs are current, acceptance criteria are complete, and no specs have gone stale. + +## Slash Commands Reference + +| Command | Purpose | When to Use | +|---------|---------|-------------| +| `/spec-init` | Bootstrap `.specs/` directory | Once per project, at project start | +| `/spec-new ` | Create a new feature spec | Starting any non-trivial feature | +| `/spec-refine ` | Validate and approve requirements | After creating a draft spec, before implementation | +| `/spec-build ` | Full implementation from spec | When the spec is approved and ready to build | +| `/spec-review ` | Verify implementation vs. spec | After manual implementation or for regression checks | +| `/spec-update` | As-built closure | After implementation (if not using `/spec-build`) | +| `/spec-check` | Health audit of all specs | Before milestones, during planning | + +## Directory Convention + +Specs live in `.specs/` at the project root, organized by domain. Each domain gets its own folder, and each feature gets its own Markdown file within that folder. + +``` +.specs/ +├── MILESTONES.md # Milestone tracker linking to feature specs +├── BACKLOG.md # Deferred items not yet scheduled +├── auth/ # Domain folder +│ ├── login-flow.md # Feature spec +│ └── oauth-providers.md # Feature spec +├── search/ # Domain folder +│ └── full-text-search.md +└── onboarding/ + └── user-signup.md +``` + +Only `MILESTONES.md` and `BACKLOG.md` live at the `.specs/` root. Everything else goes in domain subfolders. + +:::note[Spec Sizing] +Aim for roughly 200 lines per spec. If a feature needs significantly more, split it into separate specs in the domain folder. Completeness matters more than hitting a number, but very long specs are hard to load and review. +::: + +## The Approval Workflow + +The approval workflow prevents premature implementation. Here is how a spec progresses from idea to approved contract: + +**1. Draft with assumptions** — When you create a spec with `/spec-new`, every requirement is tagged `[assumed]`. This signals that the requirement reflects the spec author's best guess, not confirmed user intent. + +```markdown +## Requirements +- FR-1: The system shall send email notifications on order completion. [assumed] +- FR-2: WHEN a notification fails, the system shall retry 3 times. [assumed] +- NFR-1: Notification latency shall not exceed 5 seconds. [assumed] +``` + +**2. Refinement** — Running `/spec-refine` walks through each `[assumed]` requirement interactively. You confirm, modify, or reject each one. Confirmed requirements upgrade to `[user-approved]`. + +```markdown +## Requirements +- FR-1: The system shall send email notifications on order completion. [user-approved] +- FR-2: WHEN a notification fails, the system shall retry 3 times with exponential backoff. [user-approved] +- NFR-1: Notification latency shall not exceed 10 seconds. [user-approved] +``` + +**3. Gate check** — `/spec-build` verifies `**Approval:** user-approved` before proceeding. If any requirements remain `[assumed]`, the gate check fails and implementation is blocked. + +## Acceptance Criteria Markers + +During implementation, acceptance criteria use three states that track progress from "not started" through "implemented" to "verified": + +| Marker | Meaning | Set By | +|--------|---------|--------| +| `[ ]` | Not started — criterion has not been addressed in code | `/spec-new` (initial state) | +| `[~]` | Implemented, not yet verified — code is written but tests are not confirmed | `/spec-build` Phase 3 | +| `[x]` | Verified — tests pass, behavior confirmed | `/spec-build` Phase 4 | + +This three-state system prevents false confidence. A criterion marked `[~]` means "someone wrote code for this but nobody has verified it works." Only after a test passes (or behavior is confirmed) does it graduate to `[x]`. + +If `/spec-update` runs after manual implementation, any `[~]` markers that were never verified revert to `[ ]`. + +## The Spec Reminder Hook + +The plugin includes a `spec-reminder.py` hook that fires on the `Stop` event. When Claude finishes a turn, the hook checks two conditions: + +1. Were source code files modified? (files in `src/`, `lib/`, `app/`, `tests/`, `api/`, and other standard code directories) +2. Were any `.specs/` files also modified? + +If code changed but specs did not, the hook injects a reminder: + +> *[Spec Reminder] Code was modified in src/, tests/ but no specs were updated. Use /spec-review to verify implementation against the spec, then /spec-update to close the loop. Use /spec-new if no spec exists for this feature, or /spec-refine if the spec is still in draft status.* + +This ensures the as-built loop is always closed. The reminder only fires when a `.specs/` directory exists (meaning the project uses the spec system). + +:::note[The Reminder Is Advisory] +The spec reminder blocks the turn to surface the message, but it is not destructive. It gives you the opportunity to update specs before moving on. You can address it immediately or note it for later. +::: + +## A Practical Example + +Here is a typical workflow for implementing a "user notification preferences" feature: + +``` +1. /spec-new notification-preferences + → Creates .specs/notifications/notification-preferences.md + → Status: planned, Approval: draft + → All requirements tagged [assumed] + +2. /spec-refine notification-preferences + → Walks through each requirement interactively + → User confirms email preferences, rejects SMS for now + → Requirements upgrade to [user-approved] + → Approval: user-approved + +3. /spec-build notification-preferences + → Phase 1: Reads spec, verifies approval, explores key files + → Phase 2: Creates implementation plan, gets user approval + → Phase 3: Implements step by step, flips [ ] to [~] + → Phase 4: Runs tests, verifies criteria, upgrades [~] to [x] + → Phase 5: Updates spec status to "implemented" + +4. Done! Spec reflects what was actually built. +``` + +## Spec Template + +Every spec follows a standard structure. Here are the key sections: + +```markdown +# Feature: [Name] +**Domain:** [domain-name] +**Status:** implemented | partial | planned +**Last Updated:** YYYY-MM-DD +**Approval:** draft | user-approved + +## Intent +## Acceptance Criteria +## Key Files +## Schema / Data Model (reference file paths only) +## API Endpoints (Method | Path | Description) +## Requirements (EARS format: FR-1, NFR-1) +## Dependencies +## Out of Scope +## Resolved Questions +## Implementation Notes (post-implementation only) +## Discrepancies (spec vs reality gaps) +``` + +Requirements use the EARS (Easy Approach to Requirements Syntax) format with five patterns: Ubiquitous, Event-Driven, State-Driven, Unwanted Behavior, and Optional Feature. The `specification-writing` skill provides detailed guidance and templates for EARS format. + +## Related + +- [Specification Writing Skill](../features/skills/) — EARS format guidance and spec templates +- [Agent System](./agent-system/) — the spec-writer and architect agents support spec creation +- [Ticket Workflow](./ticket-workflow/) — tickets complement specs with issue tracking +- [Hooks](../customization/hooks/) — how the spec-reminder hook integrates +- [Commands Reference](../reference/commands/) — full command reference diff --git a/docs/src/content/docs/plugins/ticket-workflow.md b/docs/src/content/docs/plugins/ticket-workflow.md new file mode 100644 index 0000000..cf5ab03 --- /dev/null +++ b/docs/src/content/docs/plugins/ticket-workflow.md @@ -0,0 +1,155 @@ +--- +title: Ticket Workflow +description: The ticket workflow plugin integrates issue tracking with the development workflow — linking commits to tickets and managing ticket lifecycle. +sidebar: + order: 5 +--- + +The ticket workflow plugin bridges your GitHub issue tracker with your Claude Code development workflow. It automatically fetches ticket context when you reference issues, provides structured commands for creating EARS-formatted tickets, planning implementations, reviewing commits, and generating pull requests — all without leaving your coding session. + +## Automatic Ticket Linking + +The plugin's most visible feature is automatic ticket linking. When you type a prompt that mentions an issue number like `#123` or a full GitHub URL, the `ticket-linker.py` hook fetches the ticket body and injects it into Claude's context before your prompt is processed. + +This means you can say things like: + +- "Work on #42" — Claude automatically sees the full issue title, body, state, and labels +- "Fix the bug described in #108" — the issue details are available without copy-pasting +- "Review github.com/myorg/myrepo/issues/55" — full URLs work too + +The linker fires on the `UserPromptSubmit` event, runs the GitHub CLI (`gh`) to fetch the issue, and injects the ticket context as additional information. It handles up to 3 ticket references per prompt and truncates very long issue bodies to keep context manageable. + +:::tip[No Setup Required] +Ticket linking works automatically as long as the GitHub CLI is authenticated. CodeForge's devcontainer handles this for you. Just reference an issue number and the context appears. +::: + +## Ticket Lifecycle Commands + +The plugin provides four slash commands that cover the full ticket lifecycle — from creating an issue through implementation planning to pull request creation. + +### `/ticket:new` — Create a Structured Issue + +Transforms your requirements into a well-structured GitHub issue with EARS-formatted business requirements. The command guides you through a requirements gathering process: + +1. **Problem space** — what problem does this solve, who is affected, what is the current workaround? +2. **Desired outcome** — what does success look like, what is the user impact? +3. **Trigger conditions** — determines the EARS pattern (Ubiquitous, Event-Driven, State-Driven, Unwanted Behavior, or Optional Feature) +4. **Scope boundaries** — what is explicitly out of scope? +5. **Technical questions** — parked for the implementation phase, not decided now + +The output is a GitHub issue with these sections: Original Request (preserving your verbatim input), Overview, Requirements (grouped by system/component using EARS patterns), Technical Questions, and Acceptance Criteria. + +:::note[EARS Format] +EARS (Easy Approach to Requirements Syntax) uses five sentence patterns to write unambiguous requirements. For example: "WHEN a notification fails, the system shall retry 3 times with exponential backoff." The structured patterns prevent vague requirements like "the system should handle errors well." +::: + +### `/ticket:work` — Plan Implementation + +Retrieves a ticket and creates a detailed technical implementation plan. It explores your codebase to understand existing patterns, resolves technical questions from the ticket, and maps each EARS requirement to specific file changes. + +The plan is structured as phases with prerequisites, file modifications, implementation steps, and verification checklists. After you review and approve the plan, it posts the full plan as a comment on the GitHub issue — creating a permanent record of the implementation approach. + +Key features of the planning phase: +- Codebase exploration happens before any decisions are made +- Technical questions from the ticket are resolved by reading code, not guessing +- You confirm test preferences (full coverage, minimal, or none) before the plan is finalized +- All decisions and their rationale are documented in the issue comment + +### `/ticket:review-commit` — Review and Commit + +Conducts a thorough code review before committing. This is not a rubber stamp — it performs security analysis, project rules compliance checks, code quality assessment, architecture review, and requirements verification against the original ticket. + +The review process: +1. Gathers all changes (`git diff`) and the ticket context +2. Runs security checks (secrets, injection, auth, data exposure) +3. Verifies compliance with `CLAUDE.md` and `.claude/rules/` +4. Assesses code quality (complexity, duplication, naming, error handling) +5. Cross-references each EARS requirement from the ticket +6. Presents findings organized by severity (Critical, High, Medium, Low) +7. You decide for each finding: FIX, create a GitHub ISSUE, or IGNORE +8. Creates issues for deferred findings, fixes selected items, then commits + +The commit message includes business context (requirements addressed), technical changes, review findings, and a reference to the ticket number. + +### `/ticket:create-pr` — Create Pull Request with Review + +Creates a pull request and performs an aggressive security and architecture review — the final gate before merge. This goes deeper than the commit review, adding: + +- **Attack surface analysis** — every new endpoint, input vector, and permission change +- **Threat modeling** — what could an attacker exploit in each new feature +- **Dependency security** — new packages checked for CVEs, typosquatting, license issues +- **Breaking changes** — API contract changes, schema migrations, configuration additions + +The review findings are posted as a PR comment, organized by severity with file:line references. A status update is also posted back to the original ticket. + +:::caution[Never Auto-Approves] +The `/ticket:create-pr` command explicitly never approves its own pull request. It always posts "Requires human approval" — the human reviewer makes the final merge decision. +::: + +## How It All Fits Together + +A typical workflow using all four commands looks like this: + +``` +1. /ticket:new "Users need to export their data as CSV" + → Gathers requirements interactively + → Creates GitHub issue #42 with EARS-formatted requirements + +2. /ticket:work #42 + → Fetches ticket, explores codebase + → Creates phased implementation plan + → Posts plan as comment on #42 + +3. (You implement the feature, following the plan) + +4. /ticket:review-commit + → Reviews all changes against ticket #42 requirements + → Security + quality + architecture checks + → Commits with structured message referencing #42 + +5. /ticket:create-pr + → Creates PR with summary and "Closes #42" + → Runs deep security and architecture review + → Posts findings as PR comment + → Updates ticket #42 with PR status +``` + +## Integration with GitHub + +The plugin uses the GitHub CLI (`gh`) for all GitHub operations — creating issues, posting comments, creating pull requests, and fetching ticket data. It works with GitHub Issues out of the box. + +GitHub operations that the plugin performs: +- `gh issue create` — creating new tickets +- `gh issue view` — fetching ticket context (automatic linking) +- `gh issue comment` — posting plans, commit summaries, and PR status +- `gh pr create` — creating pull requests +- `gh pr review` — posting review findings (always as comments, never approvals) + +## Hook Scripts + +| Script | Event | What It Does | +|--------|-------|-------------| +| `ticket-linker.py` | UserPromptSubmit | Detects `#123` or GitHub URLs in prompts, fetches issue context via `gh`, injects it for Claude | + +The ticket linker extracts up to 3 issue references per prompt using regex patterns for both short references (`#123`) and full GitHub URLs. It caps individual issue bodies at 1500 characters and total output at 3000 characters to keep context manageable. + +## Tickets vs. Specs + +Tickets and specs serve different purposes and work well together: + +| Aspect | Tickets (`/ticket:*`) | Specs (`/spec-*`) | +|--------|----------------------|-------------------| +| **Focus** | What needs to be done (business requirements) | How it will be built (technical contract) | +| **Home** | GitHub Issues | `.specs/` directory in repo | +| **Format** | EARS requirements by system/component | Full template with schema, API, key files | +| **Lifecycle** | Create, plan, review, PR | Create, refine, build, review, update | +| **Best for** | External-facing tasks, collaboration, project management | Internal technical planning, complex features | + +For simple tasks, a ticket alone may be sufficient. For complex features that span multiple systems, you might create a ticket for tracking and a spec for detailed technical planning. + +## Related + +- [Spec Workflow](./spec-workflow/) — specifications complement tickets with detailed technical planning +- [Session Context](./session-context/) — git state injection works alongside ticket tracking +- [Agent System](./agent-system/) — agents that execute ticket-planned work +- [Commands Reference](../reference/commands/) — full command reference diff --git a/docs/src/content/docs/plugins/workspace-scope-guard.md b/docs/src/content/docs/plugins/workspace-scope-guard.md new file mode 100644 index 0000000..5e8fe60 --- /dev/null +++ b/docs/src/content/docs/plugins/workspace-scope-guard.md @@ -0,0 +1,160 @@ +--- +title: Workspace Scope Guard +description: Nuclear workspace scope enforcement — blocks all operations outside the current project directory, permanently blacklists /workspaces/.devcontainer/. +sidebar: + order: 8 +--- + +The workspace scope guard enforces hard boundaries around your current project. In a multi-project workspace, it ensures that ALL file operations and bash commands target only the project you're working in — preventing reads, writes, and command execution outside the project directory. + +## How It Works + +The plugin registers hooks across multiple events: + +| Hook Event | Script | Purpose | +|-----------|--------|---------| +| PreToolUse | `guard-workspace-scope.py` | Block out-of-scope file and bash operations | +| PreToolUse | `inject-workspace-cwd.py` | Inject CWD context alongside enforcement | +| SessionStart | `inject-workspace-cwd.py` | Set scope context at session begin | +| UserPromptSubmit | `inject-workspace-cwd.py` | Remind scope on every prompt | +| SubagentStart | `inject-workspace-cwd.py` | Ensure subagents know their scope | + +The scope guard intercepts every file-related tool call (Read, Write, Edit, NotebookEdit, Glob, Grep) **and Bash commands**. Before the tool executes, `guard-workspace-scope.py` resolves target paths and checks whether they fall within the current working directory. + +**All violations are hard-blocked** (exit code 2): + +| Operation | Out-of-Scope Behavior | +|-----------|----------------------| +| **Write, Edit, NotebookEdit** | Blocked with error message | +| **Read, Glob, Grep** | Blocked with error message | +| **Bash** | Blocked — two-layer path detection | +| **Unknown tools** | Blocked — fail closed | + +## Blacklisted Paths + +`/workspaces/.devcontainer/` is **permanently blocked** for ALL operations — reads, writes, and bash commands. This is the single most common scope escape: Claude writing to the workspace-root devcontainer instead of the project's own `.devcontainer/`. + +The blacklist: +- Runs **before** all other checks (scope, allowlist, cwd bypass) +- **Cannot be overridden**, even when cwd is `/workspaces` +- Blocks the exact path and everything under it + +## Scope Rules + +### What's In Scope + +Everything under the current working directory: + +``` +/workspaces/projects/MyProject/ -- project root (cwd) +/workspaces/projects/MyProject/src/ -- in scope +/workspaces/projects/MyProject/tests/ -- in scope +/workspaces/projects/MyProject/.specs/ -- in scope +``` + +### What's Out of Scope + +Anything outside the project root is blocked: + +``` +/workspaces/projects/OtherProject/ -- blocked (sibling project) +/workspaces/.devcontainer/ -- BLOCKED (blacklisted — always) +/workspaces/projects/MyProject2/ -- blocked (different project) +/home/vscode/ -- blocked (outside workspace) +/etc/hosts -- blocked (system path) +``` + +:::tip[Working from Workspace Root] +When your current directory is `/workspaces` (the workspace root itself), the scope guard allows operations within `/workspaces/` — **except** for blacklisted paths. `/workspaces/.devcontainer/` remains blocked even from workspace root. +::: + +### Allowlisted Paths + +A minimal set of paths are always allowed: + +| Allowed Path | Reason | +|-------------|--------| +| `/workspaces/.claude/` | Claude config, plans, rules | +| `/tmp/` | System temp directory | + +## Bash Enforcement + +Bash commands receive two-layer scope enforcement: + +### Layer 1 — Write Target Extraction + +20+ regex patterns extract file paths from write operations: redirects (`>`), cp, mv, touch, mkdir, rm, ln, rsync, chmod, chown, dd, wget -O, curl -o, tar -C, unzip -d, gcc -o, sqlite3, and more. Each extracted target is resolved and scope-checked. + +**System command exemption:** Commands like `git`, `pip`, `npm` get a Layer 1 exemption ONLY when ALL write targets resolve to system paths (`/usr/`, `/bin/`, etc.). Any `/workspaces/` write target outside cwd cancels the exemption. + +### Layer 2 — Workspace Path Scan + +A regex scans the **entire command** for any `/workspaces/` path string. This catches everything Layer 1 misses: + +- Inline scripts: `python3 -c "open('/workspaces/...')"` +- Variable assignments: `DIR=/workspaces/.devcontainer; ...` +- Quoted paths in any context +- Tool-specific flags: `pip install --target /workspaces/...` + +Layer 2 **always runs** — no exemptions, no system command bypass. + +### What Gets Through + +```bash +# ALLOWED — no /workspaces/ paths, system commands +pip install requests +git status +npm test + +# BLOCKED — writes to blacklisted path +echo test > /workspaces/.devcontainer/foo +cp file /workspaces/.devcontainer/ + +# BLOCKED — references blacklisted path (Layer 2) +python3 -c "open('/workspaces/.devcontainer/f','w')" +npm install --prefix /workspaces/.devcontainer/ + +# BLOCKED — workspace path outside cwd (Layer 2) +DIR=/workspaces/.devcontainer; echo > $DIR/foo +``` + +## Intercepted Tools + +The guard inspects different fields per tool: + +| Tool | Path Field Inspected | +|------|---------------------| +| Read | `file_path` | +| Write | `file_path` | +| Edit | `file_path` | +| NotebookEdit | `notebook_path` | +| Glob | `path` | +| Grep | `path` | +| Bash | `command` (multi-path extraction) | + +When a tool doesn't specify a path (e.g., Glob without a `path` parameter), it defaults to the current working directory, which is always in scope. + +## Error Handling + +The guard **fails closed** on all errors: + +| Scenario | Behavior | +|----------|----------| +| JSON parse failure | **Blocked** (exit 2) | +| Any exception | **Blocked** (exit 2) | +| Hook timeout | Fails open (Claude Code runtime limitation) — mitigated by 10s timeout and pure computation | + +## CWD Context Injection + +`inject-workspace-cwd.py` fires on SessionStart, UserPromptSubmit, PreToolUse, and SubagentStart to inject: + +- The current working directory +- A reminder that `/workspaces/.devcontainer/` is blacklisted +- The correct project-relative path to use instead + +This ensures Claude always knows the correct scope, even across subagent boundaries. + +## Related + +- [Dangerous Command Blocker](./dangerous-command-blocker/) — complements scope guard with command-level protection +- [Protected Files Guard](./protected-files-guard/) — guards specific files within the project diff --git a/docs/src/content/docs/reference/architecture.md b/docs/src/content/docs/reference/architecture.md new file mode 100644 index 0000000..3d52cb7 --- /dev/null +++ b/docs/src/content/docs/reference/architecture.md @@ -0,0 +1,243 @@ +--- +title: Architecture +description: System architecture overview — how CodeForge components interact, data flow, and design decisions. +sidebar: + order: 4 +--- + +This page describes how CodeForge is built -- how its components are organized, how they interact during a session, and the design principles that guide the system. CodeForge is not a standalone application. It is a DevContainer configuration that layers plugins, tools, and agents on top of Claude Code through configuration and scripts. + +## System Overview + +CodeForge operates in three layers. Each layer builds on the one below it: + +``` ++------------------------------------------------+ +| Claude Code | +| (AI assistant, tool execution, conversation) | ++------------------------------------------------+ +| CodeForge Layer | +| +----------+ +----------+ +--------------+ | +| | Plugins | | Agents | | Skills | | +| +----------+ +----------+ +--------------+ | +| +----------+ +----------+ +--------------+ | +| | Hooks | | Rules | |System Prompts| | +| +----------+ +----------+ +--------------+ | ++------------------------------------------------+ +| DevContainer | +| +----------+ +----------+ +--------------+ | +| | Runtimes | |CLI Tools | | LSP Servers | | +| +----------+ +----------+ +--------------+ | ++------------------------------------------------+ +``` + +**DevContainer layer** provides the foundation: a Python 3.14 container image with Node.js, Rust, and Bun runtimes (Go available as opt-in), plus CLI tools (ruff, biome, ast-grep, tree-sitter, and others). + +**CodeForge layer** adds intelligence: plugins register hooks that validate commands, inject context, and run quality checks. Agents provide specialized personas for different tasks. Skills offer on-demand reference material. Rules enforce hard constraints. System prompts shape behavior. + +**Claude Code layer** is the AI assistant itself, executing tools, managing conversations, and coordinating multi-agent teams. + +## Component Architecture + +### Plugin System + +Plugins are the primary extension mechanism. Each plugin is a self-contained directory with a manifest (`plugin.json`), optional hooks (`hooks/hooks.json`), and optional scripts (`scripts/`). + +**Plugin lifecycle:** + +1. **Discovery** -- Plugins are found in the marketplace directory (`.devcontainer/plugins/devs-marketplace/plugins/`) +2. **Registration** -- Plugin manifests are parsed and hooks are registered with Claude Code +3. **Activation** -- Only plugins listed as `true` in `settings.json` `enabledPlugins` are active +4. **Execution** -- Active hooks fire at their registered lifecycle points + +**Plugin isolation:** Plugins cannot directly call each other. They communicate only through the hook pipeline and shared context. This prevents coupling between plugins and makes it safe to enable or disable any plugin independently. + +### Hook Pipeline + +Hooks form a processing pipeline through Claude Code's lifecycle. Every tool use passes through this pipeline: + +``` +User Request + | + v +[PreToolUse hooks] --- block? ---> Error message to user + | + | allow + v +[Tool Execution] (Bash, Edit, Write, Read, etc.) + | + v +[PostToolUse hooks] --- inject context into conversation + | + v +Claude generates response + | + v +[Stop hooks] --- format, lint, test, notify, remind + | + v +Response shown to user +``` + +PreToolUse hooks are **gates**: any hook can block the operation. PostToolUse hooks are **enrichers**: they add context. Stop hooks are **quality checks**: they run after Claude finishes a turn. + +Additional hook points (`SessionStart`, `SubagentStart`, `TeammateIdle`, `TaskCompleted`, `UserPromptSubmit`) fire at their respective lifecycle events outside the main tool-use pipeline. + +### Agent System + +The agent system provides specialized personas with constrained tools and focus areas. CodeForge ships 17 custom agents: + +**How agent routing works:** + +1. Claude analyzes the user's request and selects an appropriate agent type +2. The `redirect-builtin-agents.py` PreToolUse hook intercepts the agent selection +3. Built-in agent types are transparently swapped for enhanced custom agents: + - `Explore` is redirected to `explorer` (fast codebase search, read-only) + - `Plan` is redirected to `architect` (implementation planning, read-only) + - `general-purpose` is redirected to `generalist` (multi-step tasks) + - `Bash` is redirected to `bash-exec` (command execution) +4. The custom agent's system prompt is loaded, restricting tools and focus +5. The agent executes within its constraints and returns results + +**Agent tiers:** Agents are grouped by capability level. Tier 1 (generalist) has all instruction blocks. Tier 2 (write agents like refactorer, test-writer, doc-writer) have full blocks. Tier 3 (read-only agents like explorer, researcher) have compact blocks. + +### Skill Loading + +Skills are Markdown knowledge files loaded on demand during a session: + +1. The **skill-suggester** UserPromptSubmit hook monitors conversation context +2. When topic keywords match a skill (e.g., "docker" maps to the Docker skill), it suggests the skill to Claude +3. The user or Claude activates the skill via its slash command (e.g., `/docker`) +4. The skill content is injected into the conversation context +5. Claude uses the skill knowledge for the current task + +CodeForge ships 34 skills across the skill-engine, spec-workflow, ticket-workflow, and agent-system plugins. + +## Directory Structure + +``` +.devcontainer/ ++-- devcontainer.json # Container definition (image, features, mounts) ++-- .env # Setup flags (SETUP_CONFIG, SETUP_ALIASES, etc.) ++-- config/ +| +-- file-manifest.json # Declarative config deployment rules +| +-- defaults/ +| +-- settings.json # Claude Code settings (model, plugins, env vars) +| +-- keybindings.json # Keyboard shortcuts +| +-- main-system-prompt.md # Development system prompt +| +-- writing-system-prompt.md # Writing mode system prompt +| +-- rules/ # Default rules deployed to .claude/rules/ +| +-- spec-workflow.md +| +-- workspace-scope.md +| +-- session-search.md ++-- features/ # DevContainer features (tool installers) +| +-- ccms/ # Session history search (Rust) +| +-- ccstatusline/ # Terminal status line +| +-- ccusage/ # API usage stats +| +-- ccburn/ # Token burn rate +| +-- claude-session-dashboard/ # Web dashboard +| +-- claude-monitor/ # Real-time monitor +| +-- ast-grep/ # Structural code search +| +-- tree-sitter/ # Syntax parsing +| +-- ruff/ # Python formatter/linter +| +-- biome/ # JS/TS formatter/linter +| +-- ... (21 features total) ++-- plugins/ +| +-- devs-marketplace/ +| +-- plugins/ +| +-- agent-system/ # 17 agents + redirection hooks +| +-- skill-engine/ # 21 skills + auto-suggestion +| +-- spec-workflow/ # 8 spec lifecycle skills +| +-- session-context/ # Git state, TODOs, commit reminders +| +-- auto-code-quality/ # Format + lint + test at Stop +| +-- dangerous-command-blocker/ # Block destructive commands +| +-- protected-files-guard/ # Block edits to sensitive files +| +-- workspace-scope-guard/ # Enforce project isolation +| +-- ticket-workflow/ # GitHub issue/PR workflow +| +-- notify-hook/ # Desktop notifications +| +-- codeforge-lsp/ # Language servers ++-- scripts/ # Setup scripts (run via postStartCommand) + +-- setup.sh # Main orchestrator + +-- setup-aliases.sh # Shell alias configuration + +-- setup-config.sh # Config file deployment + +-- setup-plugins.sh # Plugin installation + +-- setup-auth.sh # Git/NPM auth + +-- check-setup.sh # Health verification +``` + +## Design Principles + +### Configuration Over Code + +CodeForge avoids custom runtime code where possible. Behavior is defined through configuration files -- JSON manifests, Markdown prompts, and rule files -- rather than compiled programs. Hook scripts are the exception: they are small Python scripts that handle specific validation or enrichment tasks. + +### Plugin Isolation + +Each plugin operates independently. Plugins cannot directly call each other and do not share state. They communicate only through the hook pipeline (one plugin's PostToolUse output becomes part of the context that another plugin's hook sees). This isolation means you can safely enable, disable, or remove any plugin without affecting others. + +### Layered Defaults + +Configuration follows a strict override hierarchy: environment variables > project config > workspace config > defaults. You only need to specify what you want to change. Everything else falls through to sensible defaults. + +### Read-Only Safety + +Agents that do not need write access are restricted to read-only mode. This is enforced at the hook level by the `guard-readonly-bash.py` script, which blocks write operations for read-only agents. This is a security boundary, not a convention. + +### Fail-Closed Safety + +Safety-critical hooks (dangerous-command-blocker, protected-files-guard, workspace-scope-guard) fail closed: if JSON parsing fails or an unexpected error occurs, the operation is blocked rather than allowed. This prevents safety bypasses due to malformed input. + +## Data Flow + +### Container Startup + +``` +devcontainer.json + | + v +[Build] Install base image, features, runtimes, tools + | + v +[postStartCommand] setup.sh orchestrates: + 1. setup-symlink-claude.sh -- Symlink Claude config directory + 2. setup-auth.sh -- Git/NPM authentication + 3. setup-config.sh -- Deploy settings, prompts, rules via file-manifest.json + 4. setup-aliases.sh -- Write shell aliases to .bashrc/.zshrc + 5. setup-plugins.sh -- Sync plugins from marketplace + 6. setup-projects.sh -- Detect projects, configure Project Manager + 7. setup-terminal.sh -- Configure terminal settings + 8. setup-update-claude.sh -- Update Claude Code if needed (background) +``` + +### Session Lifecycle + +1. **Session start** -- User runs `cc`. Claude Code loads the system prompt, rules, CLAUDE.md files. SessionStart hooks fire (git state injection, TODO harvesting). +2. **Turn cycle** -- User input arrives. Claude selects tools. PreToolUse hooks gate each tool call. Tool executes. PostToolUse hooks enrich context. Claude generates a response. +3. **Turn boundary** -- Stop hooks fire: format edited files, lint them, run affected tests, check for uncommitted changes, remind about specs, send notifications. +4. **Session end** -- Session data is written to JSONL files for `ccms` search. + +### Context Assembly + +At session start, Claude's context is assembled from multiple sources: + +``` +System Prompt (main-system-prompt.md) + + +Rules (.claude/rules/*.md) + + +CLAUDE.md files (project root and parent directories) + + +Session Context (git state, TODOs -- injected by SessionStart hooks) + + +Skill Knowledge (injected on-demand during the session) + + +Agent System Prompt (loaded when a specific agent is activated) + = +Claude's working context for the session +``` + +## Related + +- [Plugins](../plugins/) -- detailed plugin documentation +- [Hooks](../customization/hooks/) -- hook system details and the full hook reference table +- [Configuration](../customization/configuration/) -- configuration layers and file manifest diff --git a/docs/src/content/docs/reference/changelog.md b/docs/src/content/docs/reference/changelog.md new file mode 100644 index 0000000..79fda93 --- /dev/null +++ b/docs/src/content/docs/reference/changelog.md @@ -0,0 +1,994 @@ +--- +title: Changelog +description: Complete version history for every CodeForge release — features, fixes, and migration guides. +sidebar: + order: 1 +--- + +:::note[Auto-Generated] +This page mirrors [`.devcontainer/CHANGELOG.md`](https://github.com/AnExiledDev/CodeForge/blob/main/.devcontainer/CHANGELOG.md) and is regenerated on every build. Do not edit directly — update the source file instead. +::: + +## Versioning Policy + +CodeForge follows semantic versioning: + +- **Major** (X.0.0) — Breaking changes that require migration steps +- **Minor** (0.X.0) — New features and enhancements, backward compatible +- **Patch** (0.0.X) — Bug fixes with no feature changes + +Breaking changes are rare. Most releases are minor versions that add new plugins, skills, or tools without requiring any user action beyond updating. + +## Update Process + +```bash +# Update to latest version +npx codeforge-dev@latest + +# Update to a specific version +npx codeforge-dev@1.14.0 +``` + +After updating, rebuild your DevContainer to apply changes: + +1. Open the VS Code command palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) +2. Select **Dev Containers: Rebuild Container** + +:::tip[Non-Breaking Updates] +For minor and patch updates, you can usually just rebuild the container. Check the changelog entries below for any migration notes before upgrading across multiple major versions. +::: + +## Related + +- [Installation](../getting-started/installation/) — initial setup and update instructions +- [Architecture](./architecture/) — system design context for understanding changes + +--- + +## Version History + +## v1.14.0 + +**Release date:** 2026-02-24 + +### Added + +#### Nuclear Workspace Scope Enforcement +- **Blacklist system** — `/workspaces/.devcontainer/` permanently blocked for ALL operations (read, write, bash). Checked before allowlist, scope check, and cwd bypass. Cannot be overridden, even from workspace root +- **Bash enforcement** — two-layer detection in `guard-workspace-scope.py`: + - Layer 1: 20+ regex patterns extract write targets (`>`, `tee`, `cp`, `mv`, `touch`, `mkdir`, `rm`, `ln`, `rsync`, `chmod`, `chown`, `dd`, `wget -O`, `curl -o`, `tar -C`, `unzip -d`, `gcc -o`, `sqlite3`). System command exemption only when ALL targets resolve to system paths + - Layer 2: regex scans entire command for any `/workspaces/` path string — catches inline scripts, variable assignments, quoted paths. No exemptions, always runs +- **CWD context injector** (`inject-workspace-cwd.py`) — fires on SessionStart, UserPromptSubmit, PreToolUse, SubagentStart to reinforce working directory scope +- **Fail-closed error handling** — JSON parse errors, exceptions, and unknown tools now exit 2 (block) instead of exit 0 (allow) + +#### Agent System Enhancements +- **`task-completed-check.py`** — quality gate hook (TaskCompleted) runs test suite before allowing task completion +- **`teammate-idle-check.py`** — quality gate hook (TeammateIdle) prevents teammates from going idle with incomplete tasks +- **`skills/debug/SKILL.md`** — structured log investigation skill replacing the old `/debug` slash command +- **`permissionMode`** declared on all 17 agent definitions (plan for read-only, default for write-capable) +- **Agent-system README** — full plugin documentation with hook lifecycle, agent table, quality gates + +#### Skill Engine Enhancements +- **6 new skill matchers** in `skill-suggester.py`: `spec-check`, `spec-init`, `spec-new`, `spec-refine`, `spec-update`, `team` +- **Team skill expanded** (v0.2.0) — quality gate hooks, plan approval workflow, keyboard shortcuts, use case examples, best practices, limitations +- **Skill-engine README** — full plugin documentation + +#### New Features +- **chromaterm** — terminal output colorizer via ChromaTerm2 YAML rules +- **kitty-terminfo** — xterm-kitty terminfo for Kitty terminal compatibility + +#### Documentation Site +- **Astro/Starlight docs** (`docs/`) — full documentation portal with getting-started guides, plugin reference (12 pages), feature docs, customization, and API reference +- **GitHub Actions** — `deploy-docs.yml` (docs deployment), `publish-features.yml` (GHCR feature publishing), `release.yml` (release workflow) +- **Logos** — CodeForgeLogo.png, CodeForgeLogoTr.png, github-avatar.png + +#### Plugin Installation Documentation +- **Remote install instructions** added to all 11 plugin READMEs — "From GitHub" section with clone + enabledPlugins setup from `https://github.com/AnExiledDev/CodeForge` +- **GHCR feature paths** — features README updated with `ghcr.io/anexileddev/codeforge/:` and devcontainer.json usage examples +- **READMEs added** to session-context, skill-engine, spec-workflow plugins +- **Install sections added** to workspace-scope-guard, codeforge-lsp, dangerous-command-blocker, protected-files-guard, notify-hook, ticket-workflow + +#### Other +- **Marketplace metadata** — `marketplace.json` restructured with `metadata` object, `pluginRoot`, and `keywords` arrays for all plugins +- **Port forwarding** for Claude Dashboard (port 7847) in devcontainer.json +- **ChromaTerm wrapper** in setup-aliases.sh — `cc`/`claude`/`ccw` aliases pipe through `ct` when available +- **`package.json` scripts** — added `prepublishOnly`, `docs:dev`, `docs:build`, `docs:preview` + +### Changed + +#### Workspace Scope Guard +- Reads (Read, Glob, Grep) now **hard-blocked** outside scope — upgraded from warning (exit 0) to block (exit 2) +- Allowlist trimmed to `/workspaces/.claude/` and `/tmp/` only — removed `/workspaces/.devcontainer/`, `/workspaces/.tmp/`, `/home/vscode/` +- Hook timeout increased from 5s to 10s +- Matcher expanded to include Bash tool + +#### Hook Output Schema Migration +- All hooks migrated to `hookSpecificOutput` wrapper with explicit `hookEventName` +- `commit-reminder.py` — upgraded from advisory to blocking (`decision: block`) +- `spec-reminder.py` — upgraded from advisory to blocking (`decision: block`) +- `advisory-test-runner.py` — test failures now block with `decision: block`; passes/timeouts use `systemMessage` +- `ticket-linker.py` — output wrapped in `hookSpecificOutput` +- `git-state-injector.py`, `todo-harvester.py` — output wrapped in `hookSpecificOutput` + +#### Ticket Workflow +- Migrated from slash commands to skill-based approach — 4 slash commands and system-prompt.md replaced by skills directory + +#### Skill Definitions +- All 21+ SKILL.md files rewritten with USE WHEN / DO NOT USE guidance, action-oriented descriptions, bumped to v0.2.0 +- `skill-suggester.py` keyword maps overhauled with natural phrases and concrete identifiers +- Skill suggestion output changed to mandatory directive format +- SubagentStart hook removed — suggestions now fire on UserPromptSubmit only + +#### Error Output +- `block-dangerous.py` — errors now written to stderr (was JSON on stdout) +- `guard-protected.py`, `guard-protected-bash.py` — errors now written to stderr + +#### Features +- `ccstatusline` — compact 3-line layout (was 8-line), `rawValue: true` on token widgets +- `claude-session-dashboard` — default port 3000 → 7847, `--host 0.0.0.0` for external access +- `ccms` — build cache moved from `.devcontainer/.build-cache/` to `${TMPDIR:-/tmp}/ccms-build-cache` + +#### Configuration +- `CLAUDE.md` (devcontainer) — condensed from ~308 to ~90 lines, removed redundant sections +- `spec-workflow.md` rule — condensed, defers to system prompt `` section +- `main-system-prompt.md` — expanded Agent Teams guidance: file ownership, task sizing, quality gate hooks, plan approval +- Plugin `plugin.json` files — `version` field removed across all plugins + +### Fixed +- Stale references to deleted features (mcp-reasoner, splitrail, claude-code) removed from docs +- Documentation counts updated (features: 21, agents: 17, skills: 34) +- Version mismatch in README.md corrected +- Auto-formatter/auto-linter references consolidated to auto-code-quality throughout +- Code-directive plugin references updated to agent-system, skill-engine, spec-workflow +- Personal project paths removed from .gitignore and .npmignore +- setup.js stale feature references fixed (Reasoner MCP, Go → Rust) +- `.secrets` added to .npmignore for npm publish safety +- Duplicate "### Fixed" header in v1.5.3 changelog entry +- NVM sourcing added to biome install script +- Cleanup trap added to shellcheck install script + +### Removed +- **`auto-formatter` plugin** — deleted entirely (consolidated into auto-code-quality) +- **`auto-linter` plugin** — deleted entirely (consolidated into auto-code-quality) +- **`/debug` slash command** from agent-system (replaced by debug skill) +- **4 ticket-workflow slash commands** (`ticket:new`, `ticket:work`, `ticket:review-commit`, `ticket:create-pr`) and `system-prompt.md` (replaced by skills) +- **Optional features docs** for mcp-reasoner and splitrail (features no longer exist) +- **SubagentStart hook** from skill-engine (suggestion now UserPromptSubmit only) + +--- + +## v1.13.0 + +**Release date:** 2026-02-21 + +### Fixed + +- Feature version pins: node `1.6`→`1.7.1`, github-cli `1.0`→`1.1.0`, docker-outside-of-docker `1.7`→`1.6`, rust `1.4`→`1.5.0`, claude-code `1.1`→`1.0.5` +- setup-projects.sh: suppress background inotifywait output +- agent-system: add missing `verify-tests-pass.py` and `verify-no-regression.py` (referenced by agent defs) + +### Added + +#### Plugin Architecture: Focused Plugins +- **`agent-system` plugin** — 17 custom agents with built-in agent redirection, CWD injection, and read-only bash enforcement +- **`skill-engine` plugin** — 21 coding skills with auto-suggestion hook +- **`spec-workflow` plugin** — 8 spec lifecycle skills with spec-reminder hook +- **`session-context` plugin** — session boundary hooks (git state injection, TODO harvesting, commit reminders) + +#### Other +- **`ticket-workflow` hooks** — auto-links GitHub issue/PR references in user prompts via `ticket-linker.py` +- **`auto-code-quality` advisory test runner** — runs affected tests at Stop via `advisory-test-runner.py` +- **`/team` skill** — agent team creation and management with specialist catalog (in `skill-engine`) +- **`claude-session-dashboard` feature** — local analytics dashboard for Claude Code sessions (token usage, tool calls, cost estimates, activity heatmaps). Installed globally via npm with `claude-dashboard` command. Settings persist across rebuilds via symlink to `/workspaces/.claude-dashboard/` + +### Changed + +- Plugin architecture: `code-directive` monolith replaced by focused plugins (`agent-system`, `skill-engine`, `spec-workflow`, `session-context`) +- `auto-code-quality` now consolidates `auto-formatter` + `auto-linter` (disabled separately, `auto-code-quality` is the superset) +- **`workspace-scope.md` rule hardened** — strict enforcement with no exceptions; all file operations must target paths within the current project directory + +### Removed + +- `code-directive` plugin (replaced by `agent-system`, `skill-engine`, `spec-workflow`, `session-context`) +- `auto-formatter` and `auto-linter` disabled in settings (consolidated into `auto-code-quality`) + +--- + +## v1.12.0 + +**Release date:** 2026-02-18 + +### Added + +#### Plugin README Documentation +- **9 new README files** for all marketplace plugins: auto-formatter, auto-linter, code-directive, codeforge-lsp, dangerous-command-blocker, notify-hook, protected-files-guard, ticket-workflow, workspace-scope-guard. Each documents purpose, hook lifecycle, protected patterns, and plugin structure + +#### Protected Files Guard: Bash Hook +- **`guard-protected-bash.py`** — new PreToolUse/Bash hook blocking bash commands that write to protected file paths (companion to existing Edit/Write guard). Covers `>`, `>>`, `tee`, `cp`, `mv`, `sed -i` targeting `.env`, lock files, `.git`, certificates, and credentials + +#### Devcontainer Secrets Declaration +- **`secrets` block** in devcontainer.json declaring `GH_TOKEN`, `NPM_TOKEN`, `GH_USERNAME`, `GH_EMAIL` with documentation URLs for VS Code Codespaces/devcontainer secret management + +#### Post-Start Hook System +- **`run_poststart_hooks()`** in setup.sh — runs executable `.sh` scripts from `/usr/local/devcontainer-poststart.d/`; controlled by `SETUP_POSTSTART` env flag (default: true) + +#### Git Worktree Support +- **System prompt `` section** — layout convention, creation commands, project detection, and safety rules +- **CLAUDE.md documentation** — full worktree section with layout, creation, detection, and compatibility details +- **setup-projects.sh** — `.worktrees/` explicit scanning at depth 3, `.git` file detection via `gitdir:` check, `"worktree"` tag in Project Manager +- **protected-files-guard** — `.git` regex updated from `\.git/` to `\.git(/|$)` to cover worktree `.git` pointer files + +#### Other +- **`CLAUDECODE=null` env var** — unsets the detection flag in `remoteEnv` to allow nested Claude Code sessions (claude-in-claude) +- **Go runtime option** — commented-out `ghcr.io/devcontainers/features/go:1` entry in devcontainer.json for easy opt-in + +### Changed + +#### Feature Version Pinning +- All local features pinned from `"latest"` to explicit versions: agent-browser `0.11.1`, ast-grep `0.40.5`, biome `2.4.2`, ruff `0.15.1`, pyright `1.1.408`, typescript-language-server `5.1.3`, TypeScript `5.9.3` +- External features pinned to minor versions: node `1.6`, github-cli `1.0`, docker-outside-of-docker `1.7`, uv `1.0`, rust `1.4`, claude-code `1.1` + +#### Default Shell: bash → zsh +- VS Code terminal default profile changed from bash to zsh +- Explicit `zsh` profile added to terminal profile list +- Claude Teams tmux profile shell changed from bash to zsh + +#### Security Hardening +- **dangerous-command-blocker** — 7 new blocked patterns: Docker container escape (`--privileged`, host root mount), destructive Docker ops (`stop/rm/kill/rmi`), bare force push (no branch specified), `find -exec rm`, `find -delete`, `git clean -f`, `rm -rf ../`. JSON parse failures now fail closed (exit 2 instead of 0) +- **protected-files-guard** — JSON parse failures fail closed (exit 2 instead of 0) + +#### Build & Setup +- **ccms build cache** — install.sh checks `.build-cache/bin/ccms` before cargo building; caches binary after first build for faster rebuilds; pinned to commit `f90d259a4476` +- **setup.sh** — `setup-update-claude.sh` now runs in background (non-blocking container start); script failure output displayed for diagnostics; new `background` status indicator in summary +- **inotify-tools moved to build time** — tmux feature installs inotify-tools via apt at build; setup-projects.sh no longer attempts runtime apt-get install +- **Container memory** — recommended from 4GB/8GB to 6GB/12GB in troubleshooting docs + +#### Writing System Prompt +- New **Emotional Architecture** section — cognitive-emotional loop, controlled emotion principle, autism framing for POV characters +- Expanded metaphor guidance — secondary sources beyond primary domain, "would he think this?" test +- Refined show-don't-tell rules — naming emotion permitted when it adds weight, brief internal processing after major events required +- Character profile additions — emotional architecture and trigger fields + +#### Other +- **connect-external-terminal.ps1** — tmux session directory respects `WORKSPACE_ROOT` env var with fallback +- **setup-projects.sh** — inotifywait exclude pattern narrowed from `\.git/` to `\.git` for worktree compatibility +- **README.md** — 5 new badges (changelog, last commit, npm downloads, Node.js, issues), updated tool/feature/skill counts, added Rust/Bun/ccw, changelog section +- **CLAUDE.md** — expanded ccw description, fixed Bun registry reference, documented setup-auth.sh/check-setup.sh, added CLAUDECODE/env flags/experimental vars/git worktrees/rules system sections, skill count 17→28 +- **Documentation** — `SETUP_TERMINAL`/`SETUP_POSTSTART` in configuration reference, `CLAUDECODE=null` env var, workspace-scope-guard in plugins.md +- **Agent definitions** — minor path/prompt fixes across 8 agents (claude-guide, debug-logs, dependency-analyst, explorer, generalist, git-archaeologist, researcher, security-auditor) +- **.gitignore** — added `.build-cache/` exclusion + +### Removed + +- **mcp-reasoner feature** — entire feature directory deleted (README, devcontainer-feature.json, install.sh, poststart-hook.sh) +- **splitrail feature** — entire feature directory deleted (README, devcontainer-feature.json, install.sh) + +--- + +## v1.11.0 + +**Release date:** 2026-02-17 + +### Added + +#### New Feature: ccms (Session History Search) +- **`ccms` devcontainer feature** — Rust-based CLI for searching Claude Code session JSONL files. Installed via `cargo install`. Supports boolean queries, role filtering, time scoping, project isolation, and JSON output +- **`session-search.md` rule** — global rule requiring project-scoped `ccms` usage and documenting CLI flags/query syntax +- **Rust runtime** — added `ghcr.io/devcontainers/features/rust:1` as a devcontainer feature (required by ccms) +- **System prompt `` section** — inline reference for ccms usage with key flags and examples +- **Context management updated** — `` now references ccms as the primary recovery tool for compacted sessions (three-source recovery: session history → source files → plan/requirement files) + +#### New Feature: ccw (Writing Mode) +- **`ccw` alias** — launches Claude with `writing-system-prompt.md` for creative-writing tasks +- **`writing-system-prompt.md`** — dedicated system prompt for writing mode, distributed via file-manifest + +#### New Plugin: workspace-scope-guard +- **`workspace-scope-guard`** — safety plugin that blocks writes and warns on reads outside the working directory. Registered in marketplace.json and enabled by default in settings.json + +#### New Skills: spec-build, spec-review (code-directive plugin — 28 skills total) +- **`/spec-build`** — orchestrates the full implementation lifecycle from an approved spec: plan, build, review, and close in one pass. 5-phase workflow with acceptance criteria markers (`[ ]` → `[~]` → `[x]`) +- **`/spec-review`** — standalone deep implementation review against a spec. Reads code, verifies requirements and acceptance criteria, recommends `/spec-update` when done + +#### New Hook: inject-cwd.py +- **`inject-cwd.py`** (PostToolUse, all tools) — injects current working directory into every tool response via `additionalContext` + +#### Status Line: CWD Widget +- **`ccstatusline-cwd`** — new custom-command widget showing the basename of Claude Code's working directory. Layout expanded from 7 to 8 lines (16 → 17 widgets) + +### Changed + +#### setup-aliases.sh Idempotency Fix +- **Block-marker strategy** — replaced cleanup+guard approach (which left aliases missing on re-run) with a delete-and-rewrite strategy using `START`/`END` block markers. The managed block is removed wholesale by sed range match, then always re-written fresh — no guard/`continue` needed +- **Legacy cleanup expanded** — added removal of v1.10.0 orphaned aliases/exports/`_CLAUDE_BIN`/`cc-tools()` that existed outside block markers, in addition to pre-v1.10.0 function forms +- **cc-tools expanded** — added `ccw`, `ccms`, `cargo` to the tool listing + +#### Spec Workflow: Version-Based → Domain-Based Organization +- **Directory structure** — specs now live in domain subfolders (`.specs/{domain}/{feature}.md`) instead of version directories (`.specs/v0.1.0/feature.md`) +- **ROADMAP.md → MILESTONES.md** — version tracker renamed to milestone tracker throughout all skills, templates, and system prompt +- **`**Version:**` → `**Domain:**`** — spec template metadata field renamed across spec-new template, spec-writer agent, specification-writing skill, spec-update, spec-check +- **`roadmap-template.md` → `milestones-template.md`** — reference template replaced +- **Acceptance criteria markers** — three-state progress tracking: `[ ]` (not started), `[~]` (implemented, not yet verified), `[x]` (verified). Used by `/spec-build` phases and recognized by `/spec-check` and `/spec-update` +- **Spec lifecycle expanded** — `/spec-review` inserted before `/spec-update` in the recommended post-implementation workflow. `spec-reminder.py` advisory message updated accordingly +- **Agent skill lists** — architect, generalist, and spec-writer agents gained `/spec-review` access + +#### LSP Plugin: Declarative Server Configuration +- **`codeforge-lsp/plugin.json`** — added `lspServers` block with pyright (Python), typescript-language-server (JS/TS), and gopls (Go) declarative configurations replacing implicit setup + +#### git-state-injector.py Enhancements +- **Working directory injection** — always outputs cwd with scope restriction message, even outside git repos +- **cwd from hook input** — reads `cwd` from Claude Code's hook JSON input (falls back to `os.getcwd()`) + +#### System Prompt Formatting +- **Line unwrapping** — long wrapped lines consolidated to single lines throughout (no content changes, only formatting) + +#### Documentation +- **CLAUDE.md** — added `ccw`, `ccms` commands; added `writing-system-prompt.md` to directory tree and config table; added workspace-scope-guard to plugin list; skill count 17 → 28; added Rust to `version: "none"` support; updated setup-aliases.sh description +- **README.md** — added Safety Plugins section; updated spec workflow commands/lifecycle/structure for domain-based organization; added `/spec-build` and `/spec-review` to skill table; fixed system prompt override path (`system-prompt.md` → `main-system-prompt.md`) +- **claude-guide agent** — fixed system prompt path reference (`system-prompt.md` → `main-system-prompt.md`) +- **doc-writer agent** — "Version ships" → "Milestone ships" terminology +- **marketplace.json** — skill count updated (16 → 28); workspace-scope-guard added +- **skill-suggester.py** — added keyword mappings for `spec-build` and `spec-review` +- **spec-workflow.md rule** — added `/spec-build` and `/spec-review` rules (#10, #11); added acceptance criteria markers section; updated directory convention to domain-based + +### Removed + +- **`spec-init/references/roadmap-template.md`** — replaced by `milestones-template.md` + +--- + +## v1.10.0 + +**Release date:** 2026-02-13 + +### Added + +#### New Skill: spec-refine (code-directive plugin — 26 skills total) +- **`/spec-refine`** — iterative 6-phase spec refinement: assumption mining, requirement validation (`[assumed]` → `[user-approved]`), acceptance criteria review, scope audit, and final approval gate + +#### setup-terminal.sh +- New setup script configures VS Code Shift+Enter keybinding for Claude Code multi-line terminal input (idempotent, merges into existing keybindings.json) + +### Changed + +#### Native Binary Preference +- **setup-aliases.sh** — introduces `_CLAUDE_BIN` variable resolution: prefers `~/.local/bin/claude` (official `claude install` location), falls back to `/usr/local/bin/claude`, then PATH. All aliases (`cc`, `claude`, `ccraw`) use `"$_CLAUDE_BIN"` +- **setup-update-claude.sh** — complete rewrite: delegates to `claude install` (first run) and `claude update` (subsequent starts) instead of manual binary download/checksum/swap. Logs to `/tmp/claude-update.log` + +#### Smart Test Selection +- **advisory-test-runner.py** — rewritten to run only affected tests based on edited files. Maps source files to test files (pytest directory mirroring, vitest `--related`, jest `--findRelatedTests`, Go package mapping). Timeout reduced from 60s to 15s. Skips entirely if no files edited +- **hooks.json** — advisory-test-runner timeout reduced from 65s to 20s + +#### Two-Level Project Detection +- **setup-projects.sh** — two-pass scanning: depth-1 directories with project markers registered directly; directories without markers treated as containers and children scanned. Recursive inotifywait with noise exclusion. Clean process group shutdown + +#### Spec Approval Workflow +- **spec-writer agent** — adds `**Approval:** draft` field, requires `[assumed]` tagging on all requirements, adds `## Resolved Questions` section, references `/spec-refine` before implementation +- **spec-new skill** — pre-fills `**Approval:** draft`, notes features should come from backlog +- **spec-check skill** — adds Unapproved (high) and Assumed Requirements (medium) issue checks, Approval column in health table, approval summary +- **spec-update skill** — minor alignment with approval workflow +- **spec-init templates** — backlog template expanded with P0–P3 priority grades + Infrastructure section; roadmap template rewritten with pull-from-backlog workflow +- **specification-writing skill** — updated with approval field and requirement tagging guidance + +#### Spec Workflow Completeness +- **spec-workflow.md (global rule)** — softened 200-line hard cap to "aim for ~200"; added approval workflow rules (spec-refine gate, requirement tags, spec-reminder hook); added `**Approval:**` and `## Resolved Questions` to standard template +- **main-system-prompt.md** — softened 4× hard "≤200 lines" references to "~200 lines" +- **spec-new skill** — fixed "capped at 200" internal contradiction; added explanation of what `/spec-refine` does and why +- **spec-new template** — added Approval Workflow section explaining `[assumed]`/`[user-approved]` tags and `draft`/`user-approved` status +- **spec-update skill** — added approval gate warning for draft specs; added spec-reminder hook documentation; added approval validation to checklist +- **spec-check skill** — added `implemented + draft` (High) and `inconsistent approval` (High) checks +- **spec-init skill** — expanded next-steps with full lifecycle (backlog → roadmap → spec → refine → implement → update → check) +- **spec-reminder.py** — added `/spec-refine` mention in advisory message for draft specs + +#### Documentation Sizing +- **Relaxed 200-line hard cap** to "aim for ~200 lines" across global rule, system prompt, spec-new skill, architect agent, doc-writer agent, documentation-patterns skill, and spec-check skill + +#### Other +- **setup.sh** — added `SETUP_TERMINAL` flag, normalized update-claude invocation via `run_script` helper +- **check-setup.sh** — removed checks for disabled features (shfmt, shellcheck, hadolint, dprint); checks RC files for alias instead of `type cc` +- **connect-external-terminal.sh** — uses `${WORKSPACE_ROOT:-/workspaces}` instead of hardcoded path +- **devcontainer.json** — formatting normalization +- **main-system-prompt.md** — updates for spec approval workflow and requirement tagging + +### Removed +- **test-project/README.md** — deleted (no longer needed) + +--- + +## v1.9.0 + +**Release date:** 2026-02-10 + +### Added + +#### Agent Context Inheritance (code-directive plugin) +- **Project Context Discovery** — all 14 project-interacting agents now read `.claude/rules/*.md` and CLAUDE.md files before starting work. Agents walk up the directory tree from their working directory to the workspace root, applying conventions from each level (deeper files take precedence) +- **Execution Discipline** — 7 agents (generalist, refactorer, migrator, test-writer, doc-writer, architect, researcher) gain structured pre/post-work verification: read before writing, verify after writing, no silent deviations, failure diagnosis before retry +- **Code Standards** — 5 agents (generalist full; refactorer, migrator, test-writer, architect compact) gain SOLID, DRY/KISS/YAGNI, function size limits, error handling rules, and forbidden patterns (god classes, magic numbers, dead code) +- **Professional Objectivity** — 10 agents gain explicit instruction to prioritize technical accuracy over agreement, present evidence when it conflicts with assumptions +- **Communication Standards** — all 14 agents gain response brevity rules: substance-first responses, no preamble, explicit uncertainty marking, file:line references +- **Documentation Convention** — 2 write agents (generalist, migrator) gain inline comment guidance (explain "why", not "what") +- **Context Management** — generalist gains instruction to continue working normally when context runs low +- **Testing Guidance** — generalist gains testing standards (verify behavior not implementation, max 3 mocks per test) +- **Scope Discipline** — refactorer gains explicit constraint: never expand scope beyond the requested refactoring +- **Tiered approach**: Tier 1 (generalist, 139→268 lines, all blocks), Tier 2 (4 write agents, full blocks), Tier 3 (9 read-only agents, compact blocks). 3 agents skipped (bash-exec, claude-guide, statusline-config — no project context needed) + +#### Specification Workflow System (code-directive plugin — 4 new skills, 25 total) +- **`/spec-new`** — creates a new spec from the standard template in `.specs/` +- **`/spec-update`** — performs as-built spec update after implementation (checks off criteria, adds implementation notes, updates paths) +- **`/spec-check`** — audits spec health: stale specs, missing coverage, orphaned files +- **`/spec-init`** — bootstraps `.specs/` directory structure for projects that don't have one +- **`spec-reminder.py`** `[Stop]` — new advisory hook reminds about spec updates when implementation work is detected +- **Spec skills assigned to agents** — generalist and spec-writer agents gain spec skill access in frontmatter + +#### Default Rules Distribution +- **`config/defaults/rules/`** — new directory containing default `.claude/rules/` files distributed to all projects via file-manifest +- **`spec-workflow.md`** — rule enforcing spec-before-implementation workflow, ≤200 line spec limit, `.specs/` directory convention, as-built update requirement +- **`workspace-scope.md`** — rule restricting file operations to the current project directory + +#### New Plugin: auto-code-quality +- **Self-contained code quality plugin** — combines auto-formatter + auto-linter into a single drop-in plugin with independent temp file namespace (`claude-cq-*`). Includes all 7 formatters (Ruff, Biome, gofmt, shfmt, dprint, rustfmt, Black fallback) and 7 linters (Pyright, Ruff, Biome, ShellCheck, go vet, hadolint, clippy) plus syntax validation. Designed for use outside the CodeForge devcontainer where auto-formatter and auto-linter aren't available separately + +### Changed + +#### Config System +- **`file-manifest.json`** — added 2 new entries for default rules files (`defaults/rules/spec-workflow.md`, `defaults/rules/workspace-scope.md`) targeting `${CLAUDE_CONFIG_DIR}/rules` +- **`setup-config.sh` bug fix** — fixed bash field-collapse bug where empty `destFilename` caused subsequent fields to shift. Uses `__NONE__` sentinel in jq output to prevent `read` from collapsing consecutive tab delimiters + +#### Plugin References +- **`frontend-design` plugin name corrected** — fixed `frontend-design@claude-code-plugins` → `frontend-design@claude-plugins-official` in both `settings.json` and `CLAUDE.md` + +#### Code-Directive Plugin +- **`hooks.json`** — added `spec-reminder.py` to Stop hooks (now 3 Stop hooks: advisory-test-runner, commit-reminder, spec-reminder) +- **`marketplace.json`** — added `auto-code-quality` plugin entry (10 plugins total, was 9) +- **Agent definitions** — 14 of 17 agents updated with orchestrator-mirrored instructions (see Agent Context Inheritance above) + +#### Formatting +- **Whitespace normalization** — `settings.json`, `file-manifest.json`, `marketplace.json`, `hooks.json`, `package.json`, `setup-config.sh` reformatted to consistent tab indentation + +--- + +## v1.8.0 + +**Release date:** 2026-02-09 + +### Added + +#### Config System: Declarative File Manifest +- **`config/file-manifest.json`** — new declarative manifest controlling which config files are copied and how. Replaces hardcoded `copy_file` calls with per-file `overwrite` modes: `"if-changed"` (sha256-based, default), `"always"`, or `"never"` +- **`config/defaults/`** — config files relocated from `config/` to `config/defaults/` (settings.json, keybindings.json, main-system-prompt.md) +- **`setup-config.sh` rewritten** — reads file-manifest.json, supports variable expansion (`${CLAUDE_CONFIG_DIR}`, `${WORKSPACE_ROOT}`), sha256-based change detection, and legacy fallback if manifest is missing + +#### Features +- **ruff feature** — Python formatter/linter via `uv tool install ruff`; replaces Black as primary Python formatter (Black kept as fallback) +- **shfmt feature** — Shell script formatter via direct binary download from GitHub releases; supports `.sh`, `.bash`, `.zsh`, `.mksh`, `.bats` +- **dprint feature** — Pluggable formatter for Markdown, YAML, TOML, and Dockerfile via GitHub releases binary; ships global config at `/usr/local/share/dprint/dprint.json` with four plugins (markdown, yaml, toml, dockerfile) +- **shellcheck feature** — Shell script linter via `apt-get install`; JSON output parsing for structured diagnostics +- **hadolint feature** — Dockerfile linter via direct binary download from GitHub releases; JSON output parsing + +#### Formatter Coverage (format-on-stop.py) +- **Ruff formatter** — `.py`/`.pyi` files now formatted with Ruff (falls back to Black if Ruff not installed) +- **Biome expanded** — added `.css`, `.json`, `.jsonc`, `.graphql`, `.gql`, `.html`, `.vue`, `.svelte`, `.astro` (was JS/TS only; now 18 extensions total) +- **shfmt integration** — `.sh`, `.bash`, `.zsh`, `.mksh`, `.bats` files auto-formatted on Stop +- **dprint integration** — `.md`, `.markdown`, `.yaml`, `.yml`, `.toml` files and `Dockerfile`/`.dockerfile` auto-formatted on Stop +- **rustfmt integration** — `.rs` files auto-formatted if `rustfmt` is in PATH (conditional, zero overhead when unused) + +#### Linter Coverage (lint-file.py) +- **Ruff linter** — Python files now checked by both Pyright (type checking) and Ruff (style/correctness); complementary, not redundant +- **Biome lint** — JS/TS/CSS/GraphQL files linted via `biome lint --reporter=json`; surfaces unsafe diagnostics not auto-fixed by formatter +- **ShellCheck** — shell scripts linted via `shellcheck --format=json`; structured severity/line/message output +- **go vet** — `.go` files linted via `go vet`; stderr parsed for diagnostics +- **hadolint** — `Dockerfile`/`.dockerfile` files linted via `hadolint --format json` +- **clippy** — `.rs` files linted via `cargo clippy` if cargo is in PATH (conditional) + +#### version:none Support +- **All 20 local features** now support `"version": "none"` in devcontainer.json to skip installation entirely +- Added `version` option to 7 features that previously lacked it: ccstatusline, notify-hook, shellcheck, mcp-qdrant, mcp-reasoner, splitrail, lsp-servers +- Added skip guard (`if [ "${VERSION}" = "none" ]; then exit 0; fi`) to all 20 install.sh files + +#### Advisory Hooks (code-directive plugin) +- **advisory-test-runner.py** `[Stop]` — runs project test suite on Stop, injects pass/fail results as `additionalContext`. Never blocks (always exit 0). Detects pytest, vitest, jest, mocha, go test, cargo test. 60s timeout, truncates to last 30 lines +- **git-state-injector.py** `[SessionStart]` — injects branch, status summary, recent commits, and diff stats as `additionalContext` on every session start. 5s per git command, total output capped at 2000 chars +- **ticket-linker.py** `[UserPromptSubmit]` — auto-fetches GitHub issues/PRs when prompt contains `#123` or full GitHub URLs. Up to 3 refs per prompt, body capped at 1500 chars each +- **commit-reminder.py** `[Stop]` — checks for uncommitted changes (staged/unstaged counts) and injects advisory reminder as `additionalContext`. Checks `stop_hook_active` +- **todo-harvester.py** `[SessionStart]` — greps for TODO/FIXME/HACK/XXX across 13 source extensions, injects count + top 10 items. Excludes noise dirs, output capped at 800 chars + +#### New Skills (code-directive plugin — 5 new, 21 total) +- **api-design** — REST conventions, error handling patterns, OpenAPI/Swagger guidance +- **ast-grep-patterns** — structural code search patterns across languages +- **dependency-management** — ecosystem-specific audit commands, license compliance +- **documentation-patterns** — docstring formats, API doc templates +- **migration-patterns** — Python and JavaScript framework migration guides + +#### Commands & Scripts +- **`cc-tools`** — new shell function listing all installed CodeForge tools with version info +- **`check-setup`** — new health check script (`check-setup.sh`) verifying container setup is working correctly; aliased in shell rc files + +#### Workspace +- **`CLAUDE.md`** — workspace-level project instructions (workspace scoping rules) +- **`test-project/`** — minimal test project directory + +### Changed + +#### NPM Package (setup.js) +- **`--force` is now non-destructive** — selectively syncs files instead of rm+copy. Framework files (scripts, features, plugins) are overwritten; user config files (settings, keybindings, system prompt, file-manifest) are preserved with `.codeforge-new` versions saved for diffing +- **`--reset` flag** — new option for complete fresh install (deletes and re-copies everything) +- **`.codeforge-preserve`** — user-customizable file listing additional paths to preserve during `--force` updates +- **devcontainer.json handling** — user's version backed up as `.bak` during `--force`, then overwritten with package version +- **`.npmignore`** — excludes `.codeforge-new`, `.bak`, and `.codeforge-preserve` artifacts from npm package + +#### Setup System +- **setup.sh** — removed `set -e` (individual script failures no longer abort the entire setup); structured pass/fail/skip reporting with elapsed time summary +- **setup-aliases.sh** — backs up `.bashrc`/`.zshrc` before modifying (keeps last 3 backups); cleans up old cc-tools/check-setup definitions; adds `cc-tools` function and `check-setup` alias +- **OVERWRITE_CONFIG deprecated** — replaced by per-file `overwrite` in `config/file-manifest.json`. Legacy env var triggers a deprecation warning + +#### Code-Directive Plugin +- **hooks.json** — expanded from 3 to 6 hook events (added Stop, SessionStart, updated UserPromptSubmit with ticket-linker) +- **Agent definitions** — architect gains documentation outputs section + api-design skill link; multiple agents updated with refined instructions +- **skill-suggester.py** — added keyword mappings for 5 new skills (api-design, ast-grep-patterns, dependency-management, documentation-patterns, migration-patterns) +- **specification-writing skill** — expanded with additional templates and patterns +- **code-directive plugin.json** — description updated to "17 custom agents, 16 coding skills, agent redirection, syntax validation, and skill auto-suggestion" + +#### Other +- **format-on-stop.py** — rewritten with expanded dispatch: 7 formatters covering 31 file extensions (was 3 formatters, 12 extensions) +- **lint-file.py** — rewritten as multi-language dispatcher: 7 linters across Python, JS/TS/CSS, Shell, Go, Dockerfile, Rust (was Pyright-only for Python) +- **auto-linter hook timeout** — increased from 30s to 60s (each individual linter subprocess still capped at 10s) +- **auto-formatter plugin.json** — description updated to reflect all 7 formatters +- **auto-linter plugin.json** — description updated to reflect all 7 linters +- **marketplace.json** — descriptions updated for auto-formatter, auto-linter, and code-directive plugins +- **devcontainer.json** — 5 new features registered in `overrideFeatureInstallOrder` and `features` object; added install order documentation comments +- **.env.example** — removed `OVERWRITE_CONFIG`, added `SETUP_PROJECTS`, updated descriptions +- **.gitignore** — updated with additional exclusions + +### Removed + +- **`features/claude-code/`** — entire local feature deleted (Claude Code now installed via `ghcr.io/anthropics/devcontainer-features/claude-code:1`, the official Anthropic feature) +- **`config/settings.json`**, **`config/keybindings.json`**, **`config/main-system-prompt.md`** — moved to `config/defaults/` subdirectory +- **`OVERWRITE_CONFIG` env var** — deprecated in favor of `config/file-manifest.json` per-file overwrite modes + +### Documentation + +- **New `docs/` directory** with 5 focused guides: configuration-reference, keybindings, optional-features, plugins, troubleshooting +- **CLAUDE.md** — rewritten for new config system (file-manifest.json, config/defaults/), added cc-tools/check-setup commands, added version:none section, updated plugin descriptions +- **README.md** — added new tools (ruff, shfmt, dprint, shellcheck, hadolint, Bun), updated config system docs, added SETUP_PROJECTS and PLUGIN_BLACKLIST env vars, updated ccstatusline description + +--- + +## v1.7.1 + +**Release date:** 2026-02-08 + +### Added + +- **Automatic Git & NPM auth on container start** — new `setup-auth.sh` script reads tokens from `.devcontainer/.secrets` (or environment variables) and configures GitHub CLI, git user identity, and NPM registry auth automatically +- **`.secrets.example` template** — committed template showing required variables (`GH_TOKEN`, `GH_USERNAME`, `GH_EMAIL`, `NPM_TOKEN`) +- **`.env.example` template** — committed template for environment configuration (`.env` itself remains gitignored) +- **`SETUP_AUTH` env var** — controls whether auth setup runs on container start (default: `true`) +- **`AGENT-REDIRECTION.md`** — guide on how the PreToolUse hook system works, how built-in agents are swapped to custom ones, and what else is possible (prompt injection, model overrides, conditional routing, external service chaining) + +### Changed + +- **README split by audience** — root `README.md` is now the npm/GitHub landing page (install, prerequisites, what's included, quick start); `.devcontainer/README.md` is now the usage guide (auth, tools, config, agents, keybindings, gotchas). No duplicated content between the two +- **Auto-linter moved to Stop hook** — was PostToolUse (ran pyright per-edit, caused agent re-reads); now batch-lints all edited Python files when Claude stops, matching auto-formatter's pattern. Uses its own temp file (`claude-lint-files-{session_id}`) independent of the formatter pipeline +- **`collect-edited-files.py`** — now writes to both `claude-edited-files-*` (formatter) and `claude-lint-files-*` (linter) temp files, keeping the two Stop hook pipelines independent +- **`.devcontainer/.gitignore`** — added `.secrets` explicit ignore and negation patterns (`!.env.example`, `!.secrets.example`, `!.gitignore`) to override root `.*` rule for files that should be tracked +- **`setup.sh` orchestration** — `setup-auth.sh` runs early (after symlink, before config/plugins) so NPM auth is available for plugin installation +- **`PLUGIN_BLACKLIST`** — cleared (was `"workflow-enhancer,planning-reminder"`) + +### Removed + +- **`workflow-enhancer` plugin** — deleted entirely (was scaffolding only, never active) +- **`planning-reminder` plugin** — deleted entirely (redundant with Claude Code v2.1+ auto plan mode) + +--- + +## v1.7.0 + +**Release date:** 2026-02-08 + +### Added + +- **ccburn feature** — new devcontainer feature for visual token burn rate tracking with shell aliases and statusline wrapper +- **Session resume widget** — ccstatusline displays copyable `cc --resume {sessionId}` command on line 5 +- **Burn rate widget** — ccstatusline line 6 shows live ccburn compact output with pace indicators (session/weekly/sonnet limits) +- **17 custom agent definitions** — code-directive plugin now includes specialized agents: architect, bash-exec, claude-guide, debug-logs, dependency-analyst, doc-writer, explorer, generalist, git-archaeologist, migrator, perf-profiler, refactorer, researcher, security-auditor, spec-writer, statusline-config, test-writer +- **6 new skills** — claude-agent-sdk, git-forensics, performance-profiling, refactoring-patterns, security-checklist, specification-writing +- **Agent redirect hook** — `redirect-builtin-agents.py` (PreToolUse/Task) transparently swaps built-in agent types (Explore→explorer, Plan→architect, etc.) to enhanced custom agents +- **Readonly bash guard** — `guard-readonly-bash.py` blocks write operations for read-only agents +- **Regression test hooks** — `verify-no-regression.py` (PostToolUse for refactorer) and `verify-tests-pass.py` (Stop for test-writer) +- **REVIEW-RUBRIC.md** — quality standards document for agent/skill development +- **Keybindings configuration** — new `config/keybindings.json` with schema support +- **VS Code terminal passthrough** — `Ctrl+P` and `Ctrl+F` pass through to Claude Code via `terminal.integrated.commandsToSkipShell` +- **claude-agent-sdk skill** — new code-directive skill for Claude Agent SDK TypeScript integration +- **OVERWRITE_CONFIG documentation** — documented ephemeral settings behavior +- **Project Manager integration** — `setup-projects.sh` auto-detects projects under `/workspaces/`, watches for changes via inotifywait, maintains `projects.json` +- **Claude config symlink** — `setup-symlink-claude.sh` symlinks `~/.claude` → `$CLAUDE_CONFIG_DIR` for third-party tool compatibility +- **Project Manager VS Code extension** — `alefragnani.project-manager` added to devcontainer + +### Changed + +- **ccstatusline layout** — expanded from 3→6 lines (13→16 widgets), reorganized into logical groups (core metrics, tokens, git, session, totals, burn rate) +- **ccstatusline version** — bumped from 1.0.0 to 1.1.0 +- **Plugin declarations centralized** — all 9 marketplace plugins declared in `enabledPlugins` in `config/settings.json` +- **setup-plugins.sh cache sync** — re-added plugin install loop to sync cache from source on every container start; added `.env` fallback so `PLUGIN_BLACKLIST` works on standalone invocation +- **Feature-level config synced** — `features/claude-code/config/settings.json` mirrors main config (model → `claude-opus-4-6`, `MAX_THINKING_TOKENS` → `63999`, `cleanupPeriodDays` → `60`, all env vars) +- **8 new env vars** — `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY`, `CLAUDE_CODE_MAX_RETRIES`, `BASH_MAX_OUTPUT_LENGTH`, `TASK_MAX_OUTPUT_LENGTH`, `CLAUDE_CODE_PLAN_MODE_INTERVIEW_PHASE`, `CLAUDE_CODE_PLAN_V2_AGENT_COUNT`, `CLAUDE_CODE_PLAN_MODE_REQUIRED`, `CLAUDE_CODE_FORCE_GLOBAL_CACHE` +- **setup-config.sh** — added `chown` for correct ownership; added keybindings.json to copy pipeline +- **setup-aliases.sh** — added idempotency guard +- **TMPDIR consistency** — `setup-update-claude.sh` and `ccstatusline/install.sh` use `${TMPDIR:-/tmp}` +- **installsAfter references** — mcp-qdrant and mcp-reasoner updated from `./features/claude-code` to `ghcr.io/anthropics/devcontainer-features/claude-code:1` +- **code-directive hooks.json** — added PreToolUse/Task hook for agent redirection +- **Auto-linter timeout** — pyright reduced from 55s to 10s +- **Auto-formatter tool paths** — resolved via `which` first +- **Protected-files-guard regex** — tightened `id_rsa` pattern +- **Syntax-validator JSONC regex** — handles URLs containing `://` +- **Skill-suggester keywords** — consolidated claude-agent-sdk phrases; added "compose" to docker +- **redirect-builtin-agents.py fix** — `updatedInput` now preserves all original tool input fields (Claude Code replaces rather than merges) +- **System prompt hardened** — added anti-fabrication rule, failure recovery strategy, and silent-violation guard to `execution_discipline` and `rule_precedence` + +### Removed + +- **setup-irie-claude.sh** — deleted (personal script, no longer invoked) +- **output-style widget** — removed from ccstatusline (low value) + +### Documentation + +- **CLAUDE.md** — added keybindings.json, updated plugins list, fixed model name, documented VS Code conflicts, documented OVERWRITE_CONFIG, added agents/skills sections, added new scripts +- **README.md** — fixed max output tokens, added keybindings section, added agents/skills, added project manager +- **features/README.md** — full rewrite listing all features +- **CHANGELOG.md** — squashed v1.6.0 + v1.6.1 into this entry + +--- + +## v1.5.8 + +**Release date:** 2026-02-06 + +### Changed + +- **tmux is now opt-in in VS Code**: Reverted auto-tmux-everywhere approach (forced all terminals into tmux, caused shared-view conflicts and hotkey clashes with Claude Code). Default terminal is plain `bash`. A **"Claude Teams (tmux)"** profile is available from the VS Code terminal dropdown for Agent Teams split-pane sessions. External terminal connectors (WezTerm/iTerm2) are unchanged — they still auto-enter tmux +- **Removed auto-tmux from `.bashrc`/`.zshrc`**: The `exec tmux` block that forced every interactive shell into tmux has been removed from `setup-aliases.sh` + +--- + +## v1.5.3 + +**Release date:** 2026-02-06 + +### Added + +- **Catppuccin Mocha tmux theme**: Replaced barebones tmux config with Catppuccin v2.1.3. Rounded window tabs, Nerd Font icons, transparent status bar, colored pane borders. Installed at build time via shallow git clone (~200KB, ~2s) + +### Fixed + +- **ccstatusline powerline glyphs**: Powerline separators/caps were empty strings, rendering as underscores. Now uses proper Nerd Font glyphs (U+E0B0, U+E0B4, U+E0B6) +- **Unicode rendering in external terminals**: tmux rendered ALL Unicode as underscores because `docker exec` doesn't propagate locale vars. External terminal scripts now pass `LANG`/`LC_ALL=en_US.UTF-8` and use `tmux -u` to force UTF-8 mode. Locale exports also added to `.bashrc`/`.zshrc` as permanent fallback + +- **cc/claude aliases**: Converted from shell functions to simple aliases — functions were not reliably invoked across shell contexts (tmux, docker exec, external terminals), causing Claude to launch without config +- **CLAUDE_CONFIG_DIR export**: Now exported in `.bashrc`/`.zshrc` directly, so credentials are found in all shells (not just VS Code terminals where `remoteEnv` applies) + +--- + +## v1.5.0 + +**Release date:** 2026-02-06 + +### Added + +#### Agent Teams (Experimental) +- **Claude Code Agent Teams**: Enabled via `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1"` and `teammateMode: "auto"` +- **System prompt guidance**: Agent Teams section with 3–5 active teammate limit and usage heuristics +- **Task tracking**: `CLAUDE_CODE_ENABLE_TASKS: "true"` for structured task management +- **Effort level**: `CLAUDE_CODE_EFFORT_LEVEL: "high"` + +#### Features +- **tmux feature**: Split-pane terminal multiplexer for Agent Teams + - Pre-configured Catppuccin color palette, mouse support, 10,000-line scrollback + - Creates `claude-teams` session on container start +- **Biome feature**: Fast JS/TS/JSON/CSS formatter via global `@biomejs/biome` install +- **External terminal connectors**: Bash (`.sh`) and PowerShell (`.ps1`) scripts to connect host terminals to devcontainer tmux sessions +- **Claude Code auto-update**: `setup-update-claude.sh` checks for newer Claude Code native binary on every container start + - Runs non-blocking in background via `setup.sh` + - Downloads from GCS, verifies SHA256 checksum, atomic binary replacement + - Controlled by `SETUP_UPDATE_CLAUDE` env var in `.env` (default: `true`) + +#### Plugins +- **code-directive plugin**: Replaces `codedirective-skills` with expanded hook infrastructure + - **New skill**: `debugging` — Log forensics, Docker log analysis, error pattern recognition + - **Hooks**: `skill-suggester.py` (UserPromptSubmit, SubagentStart), `syntax-validator.py` + `collect-edited-files.py` (PostToolUse) + - All 10 existing skills migrated from `codedirective-skills` + +#### VS Code Extensions +- `GitHub.vscode-github-actions` — GitHub Actions workflow support +- `fabiospampinato.vscode-todo-plus` — Todo+ task management + +### Changed + +- **Default model**: Claude Opus 4-5 → **Claude Opus 4-6** (frontier) +- **Max output tokens**: 64,000 → **128,000** +- **Container memory**: 3GB → **4GB** (`--memory-swap` raised to 8GB) +- **External terminal connectors**: Now run as `vscode` user and auto-launch `cc` on new tmux sessions +- **Auto-formatter**: Switched from PostToolUse (`format-file.py`) to Stop hook (`format-on-stop.py`) + - Added Biome support for JS/TS/CSS alongside existing Black and gofmt + - Batch-formats all edited files when Claude stops instead of formatting on every edit +- **Auto-linter**: Switched from PostToolUse to Stop hook +- **Agent-browser**: Optimized to install only Chromium (previously installed all Playwright browsers) + +### Removed + +- **codedirective-skills plugin**: Replaced by `code-directive` (all skills preserved) +- **format-file.py**: Replaced by `format-on-stop.py` +- **`CLAUDE_CODE_SUBAGENT_MODEL`**: Environment variable removed (no longer needed) + +### Gitignore + +- Added `claude-dev-discord-logs/`, `devforge/` + +--- + +## v1.4.0 + +**Release date:** 2026-02-01 + +### Breaking + +- **Package rename**: `claudepod` → `codeforge-dev` on npm. Install via `npx codeforge-dev` +- **Full rebrand**: All references renamed from ClaudePod/claudepod to CodeForge/codeforge + +### Added + +#### Plugins +- **codedirective-skills plugin**: 9 coding reference skills for the CodeDirective tech stack + - `fastapi` - Routing, middleware, SSE, Pydantic models + - `pydantic-ai` - Agents, tools, models, streaming + - `svelte5` - Runes, reactivity, components, routing, dnd, LayerCake, AI SDK + - `sqlite` - Python/JS patterns, schema, pragmas, advanced queries + - `docker` - Dockerfile patterns, Compose services + - `docker-py` - Container lifecycle, resources, security + - `claude-code-headless` - CLI flags, output, SDK/MCP + - `testing` - FastAPI and Svelte testing patterns + - `skill-building` - Meta-skill for authoring skills +- **codeforge-lsp plugin**: Replaces `claudepod-lsp` with identical functionality +- **Svelte MCP plugin**: Added `svelte@sveltejs/mcp` to official plugins +- **Plugin blacklist system**: `PLUGIN_BLACKLIST` env var in `.env` to skip plugins during auto-install + - Parsed by `is_blacklisted()` helper in `setup-plugins.sh` + - Default: `workflow-enhancer` blacklisted + +#### System Prompt +- **``**: Verify before assuming, read before writing, instruction fidelity, verify after writing, no silent deviations +- **``**: Prioritize technical accuracy over agreement, direct measured language +- **``**: ast-grep and tree-sitter usage guidance with when-to-use-which +- **Scope discipline**: Modify only what the task requires, trust internal code, prefer inline clarity +- **Continuation sessions**: Re-read source files after compaction, verify state before changes +- **Brevity additions**: No problem restatement, no filler/narrative, no time estimates + +#### DevContainer +- **Bun runtime**: Added `ghcr.io/rails/devcontainer/features/bun:1.0.2` +- **Playwright browsers**: Installed via `npx playwright install --with-deps` in agent-browser feature +- **Memory cap**: Container limited to 3GB via `--memory=3g --memory-swap=3g` +- **TMPDIR**: Set to `/workspaces/.tmp` +- **VS Code remote extension**: `wenbopan.vscode-terminal-osc-notifier` configured as UI extension + +### Changed + +- **Permission model**: `--dangerously-skip-permissions` → `--permission-mode plan --allow-dangerously-skip-permissions` +- **Settings**: `autoCompact: true`, `alwaysThinkingEnabled: true` +- **Autocompact threshold**: 80% → 95% +- **Cleanup period**: 360 days → 60 days +- **Tool search**: Added `ENABLE_TOOL_SEARCH: "auto:5"` +- **Tree-sitter**: Removed Go grammar from defaults +- **Ticket-workflow commands**: Renamed `ticket:` → `ticket꞉` for cross-platform filesystem compatibility +- **notify-hook**: Added empty `matcher` field to hooks.json schema + +### Removed + +- **claudepod-lsp plugin**: Replaced by `codeforge-lsp` + +### Gitignore + +- Added `code-directive/`, `article/`, `claude-research/`, `dashboard/`, `simple-review/`, `workflow-enhancer/` + +--- + +## v1.3.1 + +**Release date:** 2025-01-24 + +### Fixed + +- **Plugin installation**: Fixed invalid plugin.json schema causing installation failures + - Removed `$schema`, `category`, `version`, `lspServers` keys from individual plugin.json files + - These fields now correctly reside only in `marketplace.json` +- **setup-plugins.sh**: Fixed path resolution for marketplace discovery + - Changed from `${containerWorkspaceFolder:-.}` to `SCRIPT_DIR` relative path + - Script now works correctly regardless of working directory + +### Changed + +- **Consolidated LSP setup**: Merged `setup-lsp.sh` into `setup-plugins.sh` + - Single script now handles both official and local marketplace plugins + - Removed `SETUP_LSP` environment variable (no longer needed) +- **settings.json**: Updated Claude Code configuration + - Increased `MAX_THINKING_TOKENS` from 14999 to 63999 + - Added `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`: 80 (auto-compact at 80% context) + - Added `CLAUDE_CODE_SHELL`: zsh + - Added `FORCE_AUTOUPDATE_PLUGINS`: true + - Added `autoUpdatesChannel`: "latest" + +### Removed + +- **setup-lsp.sh**: Deleted (functionality consolidated into setup-plugins.sh) + +--- + +## v1.3.0 + +**Release date:** 2025-01-24 + +### Added + +#### Code Quality Hooks +- **dangerous-command-blocker**: PreToolUse hook blocks dangerous bash commands + - Blocks `rm -rf /`, `rm -rf ~`, `sudo rm`, `chmod 777` + - Blocks `git push --force` to main/master + - Blocks writes to system directories (`/usr`, `/etc`, `/bin`) + - Blocks disk formatting (`mkfs.*`, `dd of=/dev/`) +- **protected-files-guard**: PreToolUse hook blocks modifications to sensitive files + - Blocks `.env`, `.env.*` environment files + - Blocks `.git/` directory + - Blocks lock files (`package-lock.json`, `yarn.lock`, `poetry.lock`, etc.) + - Blocks certificates/keys (`.pem`, `.key`, `.crt`) + - Blocks credential files and auth directories (`.ssh/`, `.aws/`) +- **auto-formatter**: PostToolUse hook auto-formats edited files + - Python files via Black (`/usr/local/py-utils/bin/black`) + - Go files via gofmt (`/usr/local/go/bin/gofmt`) +- **auto-linter**: PostToolUse hook auto-lints edited files + - Python files via Pyright with JSON output parsing +- **planning-reminder**: PreToolUse hook encourages plan-before-implement workflow + +#### Features +- **notify-hook feature**: Desktop notifications when Claude finishes responding + - OSC escape sequences for terminal notification support + - Optional audio bell + - VS Code extension recommendation for terminal notifications +- **agent-browser feature**: Headless browser automation CLI for AI agents + - Accessibility tree snapshots for AI navigation + - Screenshots and PDF capture + - Element interaction and cookie management +- **Go LSP (gopls)**: Full Go language server support + - Added `gopls` to codeforge-lsp plugin configuration + - Added `goplsVersion` option to lsp-servers feature + - Supports `.go`, `.mod`, `.sum` file extensions +- **Go language**: Added `ghcr.io/devcontainers/features/go:1` feature + +#### Plugins +- **ticket-workflow plugin**: EARS-based ticket workflow with GitHub integration + - `/ticket:new` - Transform requirements into EARS-formatted GitHub issues + - `/ticket:work` - Create technical implementation plans from tickets + - `/ticket:review-commit` - Thorough code review with requirements verification + - `/ticket:create-pr` - Create PRs with aggressive security/architecture review +- **notify-hook plugin**: Claude Code hook integration for completion notifications +- **codeforge-lsp plugin.json**: Proper plugin structure for LSP servers + +#### Commands & Aliases +- **ccraw alias**: Runs vanilla Claude Code without any config + - Bypasses the function override via `command claude` + - Useful for debugging or running without custom system prompt + +#### Documentation +- **System prompt**: Added `` section with all available tools +- **System prompt**: Added `` section with usage guidance + +### Changed + +- **claude command**: Now behaves the same as `cc` (auto-creates local config) + - Uses `command claude` internally to call the actual binary + - Both `claude` and `cc` auto-setup `.claude/system-prompt.md` and `.claude/settings.json` +- **Container name**: Now includes project folder name for multi-project clarity + - Format: `CodeForge - ${localWorkspaceFolderBasename}` +- **setup-lsp.sh**: Replaced hard-coded plugin list with dynamic discovery + - Now reads all plugins from `marketplace.json` using `jq` + - Automatically installs new plugins when added to marketplace +- **System prompt**: Updated to use correct Claude Code tool names + - Fixed plan mode references: `PlanMode` → `EnterPlanMode` / `ExitPlanMode` + - Added explicit tool names throughout directives +- **Plugin installation**: Reduced from 7 plugins to 1 official plugin (frontend-design skill) + +### Removed + +- `code-review@claude-plugins-official` (command plugin) +- `commit-commands@claude-plugins-official` (command plugin) +- `pr-review-toolkit@claude-plugins-official` (command + agent plugin) +- `code-simplifier` npx installation block + +### Files Created + +``` +.devcontainer/ +├── features/ +│ ├── agent-browser/ +│ │ ├── devcontainer-feature.json +│ │ ├── install.sh +│ │ └── README.md +│ └── notify-hook/ +│ ├── devcontainer-feature.json +│ ├── install.sh +│ └── README.md +└── plugins/devs-marketplace/plugins/ + ├── auto-formatter/ + │ ├── .claude-plugin/plugin.json + │ ├── hooks/hooks.json + │ └── scripts/format-file.py + ├── auto-linter/ + │ ├── .claude-plugin/plugin.json + │ ├── hooks/hooks.json + │ └── scripts/lint-file.py + ├── codeforge-lsp/ + │ └── .claude-plugin/plugin.json + ├── dangerous-command-blocker/ + │ ├── .claude-plugin/plugin.json + │ ├── hooks/hooks.json + │ └── scripts/block-dangerous.py + ├── notify-hook/ + │ ├── .claude-plugin/plugin.json + │ └── hooks/hooks.json + ├── planning-reminder/ + │ ├── .claude-plugin/plugin.json + │ └── hooks/hooks.json + ├── protected-files-guard/ + │ ├── .claude-plugin/plugin.json + │ ├── hooks/hooks.json + │ └── scripts/guard-protected.py + └── ticket-workflow/ + └── .claude-plugin/ + ├── plugin.json + ├── system-prompt.md + └── commands/ + ├── ticket:new.md + ├── ticket:work.md + ├── ticket:review-commit.md + └── ticket:create-pr.md +``` + +### Files Modified + +- `.devcontainer/devcontainer.json` - Added features, VS Code settings, dynamic name +- `.devcontainer/config/main-system-prompt.md` - Tools reference, browser automation +- `.devcontainer/scripts/setup-aliases.sh` - Claude function override, ccraw alias +- `.devcontainer/scripts/setup-lsp.sh` - Dynamic plugin discovery +- `.devcontainer/scripts/setup-plugins.sh` - Trimmed to frontend-design only +- `.devcontainer/features/lsp-servers/install.sh` - Added gopls installation +- `.devcontainer/features/lsp-servers/devcontainer-feature.json` - Added goplsVersion +- `.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json` - All new plugins +- `.devcontainer/CLAUDE.md` - Updated plugin docs, local marketplace section +- `.devcontainer/README.md` - Added agent-browser, Go to tools tables + +--- + +## v1.2.3 + +**Release date:** 2025-01-19 + +### Changed +- Added `--force` flag support +- Removed devpod references + +--- + +## v1.2.0 + +**Release date:** 2025-01-19 + +### Added +- **GitHub CLI**: Added `ghcr.io/devcontainers/features/github-cli:1` feature +- **Official Anthropic Plugins**: New `setup-plugins.sh` script +- **SETUP_PLUGINS** environment variable +- **GitHub CLI Credential Persistence**: `GH_CONFIG_DIR=/workspaces/.gh` +- **README.md**: Comprehensive documentation +- **CLAUDE.md**: Development guide for Claude Code + +### Changed +- **Plan Mode Default**: Changed `defaultMode` from `"dontAsk"` to `"plan"` +- **cc Command**: Replaced simple alias with smart function + +### Removed +- **Specwright**: Completely removed (setup script, aliases, plugin files, ORCHESTRATOR.md) diff --git a/docs/src/content/docs/reference/commands.md b/docs/src/content/docs/reference/commands.md new file mode 100644 index 0000000..43e49ab --- /dev/null +++ b/docs/src/content/docs/reference/commands.md @@ -0,0 +1,193 @@ +--- +title: Commands +description: Complete reference table of all CLI commands, aliases, and slash commands available in CodeForge. +sidebar: + order: 2 +--- + +All CLI commands and slash commands available in the CodeForge DevContainer. Commands are shell aliases and functions defined in `setup-aliases.sh` and deployed to `.bashrc` and `.zshrc` on container start. + +## Session Commands + +Commands for launching and managing Claude Code sessions. + +| Command | Description | Example | +|---------|-------------|---------| +| `cc` | Launch Claude Code with the main system prompt, plugins, and plan mode | `cc` | +| `claude` | Identical to `cc` | `claude` | +| `ccw` | Launch Claude Code with the writing system prompt (for docs and prose) | `ccw` | +| `ccraw` | Launch vanilla Claude Code with no custom config, prompts, or plugins | `ccraw` | + +All session commands auto-detect the Claude binary location: `~/.local/bin/claude` (native install) is preferred, then `/usr/local/bin/claude`, then PATH lookup. If ChromaTerm (`ct`) is installed, output is wrapped through it for color highlighting. + +:::caution[Permissions Flag] +The `cc`, `claude`, and `ccw` aliases include the `--allow-dangerously-skip-permissions` flag, which enables non-interactive permission handling. The aliases also set `CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1` so Claude reads CLAUDE.md files from parent directories. Use `ccraw` if you need a session without these flags or env vars. +::: + +:::tip[Resuming Sessions] +Use `cc --resume ` to resume a previous session. The session ID is displayed in the status line during active sessions. +::: + +## Analysis and Monitoring Commands + +Commands for session analysis, usage tracking, and system monitoring. + +| Command | Description | Example | +|---------|-------------|---------| +| `ccms` | Search Claude Code session history. Supports boolean queries, role filtering, time scoping, and project isolation. | `ccms --project "$(pwd)" "auth approach"` | +| `ccusage` | View Claude API usage statistics | `ccusage` | +| `ccburn` | Analyze token burn rate and consumption patterns with pace indicators | `ccburn` | +| `ccstatusline` | Terminal status line displaying session metrics, git state, token usage, and burn rate | (runs automatically) | +| `claude-dashboard` | Web-based session monitoring dashboard on port 7847 with cost estimates and activity heatmaps | `claude-dashboard` | +| `claude-monitor` | Real-time Claude session activity monitor | `claude-monitor` | +| `agent-browser` | Headless Chromium browser for agent automation with accessibility tree snapshots | `agent-browser` | +| `check-setup` | Verify CodeForge installation health -- checks tools, config, and aliases | `check-setup` | +| `cc-tools` | List all installed CodeForge CLI tools with version info | `cc-tools` | + +### ccms Usage + +`ccms` is the most feature-rich analysis command. Key flags: + +```bash +# Basic search +ccms "error handling" + +# Project-scoped (recommended) +ccms --project "$(pwd)" "auth approach" + +# Filter by role +ccms -r assistant "what was decided" +ccms -r user "please fix" + +# Boolean queries +ccms "error AND connection" +ccms "(auth OR authentication) AND NOT test" + +# Time-scoped +ccms --since "1 day ago" "recent work" + +# JSON output +ccms -f json "query" -n 10 +``` + +## Code Quality Commands + +Pre-installed tools for linting, formatting, and code analysis. + +| Command | Languages | Purpose | Example | +|---------|-----------|---------|---------| +| `ruff` | Python | Fast linting and formatting (replaces Black + Flake8) | `ruff check . --fix` | +| `biome` | JS/TS/JSON/CSS | Unified linting and formatting | `biome check .` | +| `shellcheck` | Shell | Script linting with structured diagnostics | `shellcheck script.sh` | +| `shfmt` | Shell | Script formatting | `shfmt -w script.sh` | +| `dprint` | MD/TOML/YAML | Pluggable multi-language formatter | `dprint fmt` | +| `hadolint` | Dockerfile | Dockerfile best practice linting | `hadolint Dockerfile` | + +:::note[Optional Tools] +Some code quality tools ship with `"version": "none"` in `devcontainer.json` (disabled by default). To enable them, set a specific version or `"latest"` in the feature configuration and rebuild the container. +::: + +## Code Intelligence Commands + +Commands for structural code search and syntax analysis. These tools understand code structure (AST) rather than treating source files as plain text. + +| Command | Purpose | Example | +|---------|---------|---------| +| `ag` / `sg` | ast-grep -- structural code search using AST patterns. Find code by structure, not text. | `sg -p 'console.log($$$)' -l js` | +| `tree-sitter` | Tree-sitter CLI -- parsing, syntax tree operations, and grammar development | `tree-sitter parse file.py` | + +### ast-grep Examples + +```bash +# Find all console.log statements in JavaScript +sg -p 'console.log($$$)' -l js + +# Find functions with more than 3 parameters in Python +sg -p 'def $FUNC($A, $B, $C, $D, $$$)' -l python + +# Find unused imports in TypeScript +sg -p 'import { $NAME } from $_' -l ts +``` + +### tree-sitter Examples + +```bash +# Parse a file and show the syntax tree +tree-sitter parse file.py + +# Highlight a file with syntax colors +tree-sitter highlight file.py +``` + +## Spec Workflow Slash Commands + +Slash commands for specification-driven development. These are used within Claude Code sessions (type them in the chat, not the shell). + +| Command | Purpose | Example | +|---------|---------|---------| +| `/spec-init` | Bootstrap the `.specs/` directory with templates | `/spec-init` | +| `/spec-new ` | Create a new feature specification from the standard template | `/spec-new user-signup` | +| `/spec-refine ` | Validate assumptions, get user approval before implementation | `/spec-refine user-signup` | +| `/spec-build ` | Orchestrate full implementation: plan, build, review, and close | `/spec-build user-signup` | +| `/spec-review ` | Verify implementation against spec requirements | `/spec-review user-signup` | +| `/spec-update` | As-built spec closure after implementation | `/spec-update` | +| `/spec-check` | Audit spec health -- find stale, incomplete, or unapproved specs | `/spec-check` | + +## Ticket Workflow Slash Commands + +Slash commands for issue and ticket management within Claude Code sessions. + +| Command | Purpose | +|---------|---------| +| `/ticket:new` | Create a new GitHub issue in EARS format | +| `/ticket:work` | Start working on a ticket with a technical implementation plan | +| `/ticket:create-pr` | Generate a PR from ticket context with security review | +| `/ticket:review-commit` | Review commits against ticket requirements | + +## GitHub CLI + +The GitHub CLI (`gh`) is pre-installed for repository operations. + +| Command | Purpose | Example | +|---------|---------|---------| +| `gh issue list` | List repository issues | `gh issue list --state open` | +| `gh issue view` | View issue details | `gh issue view 42` | +| `gh pr create` | Create a pull request | `gh pr create --title "Add feature"` | +| `gh pr view` | View pull request details | `gh pr view 15` | +| `gh api` | Make authenticated GitHub API requests | `gh api repos/owner/repo/pulls` | + +## Other Useful Commands + +These additional commands are available in the container environment: + +| Command | Purpose | +|---------|---------| +| `git` | Version control (pre-configured with worktree support) | +| `docker` | Container management via Docker-outside-of-Docker | +| `jq` | JSON processing and filtering | +| `tmux` | Terminal multiplexer for Agent Teams split-pane sessions | +| `bun` | Fast JavaScript runtime and package manager | +| `cargo` | Rust package manager (used by ccms) | +| `uv` | Fast Python package installer | + +## Command Sources + +Commands come from different sources in the CodeForge setup: + +| Source | Commands | How Defined | +|--------|----------|-------------| +| Shell aliases | `cc`, `claude`, `ccw`, `ccraw`, `check-setup` | `setup-aliases.sh` writes to `.bashrc`/`.zshrc` | +| Shell functions | `cc-tools` | `setup-aliases.sh` writes to `.bashrc`/`.zshrc` | +| DevContainer features | `ccms`, `ccusage`, `ccburn`, `ruff`, `biome`, `sg`, etc. | `install.sh` in each feature directory | +| Slash commands | `/spec-new`, `/ticket:new`, etc. | Skill SKILL.md files in plugin directories | +| External features | `gh`, `docker`, `node`, `bun`, `cargo` | Installed via `devcontainer.json` features | + +:::tip[Listing All Tools] +Run `cc-tools` to see every installed tool and its version. This is the quickest way to verify what is available in your container. +::: + +## Related + +- [CLI Tools](../features/tools/) -- detailed tool descriptions and usage examples +- [Spec Workflow](../plugins/spec-workflow/) -- specification command details and lifecycle +- [Environment Variables](./environment/) -- env vars that affect command behavior diff --git a/docs/src/content/docs/reference/environment.md b/docs/src/content/docs/reference/environment.md new file mode 100644 index 0000000..f6afe75 --- /dev/null +++ b/docs/src/content/docs/reference/environment.md @@ -0,0 +1,165 @@ +--- +title: Environment Variables +description: Complete reference of all environment variables used by CodeForge and its plugins. +sidebar: + order: 3 +--- + +Environment variables control CodeForge runtime behavior. They can be set in `devcontainer.json`, the `settings.json` env block, your shell profile, or per-session on the command line. + +## Claude Code Variables + +Variables that control Claude Code's core behavior inside the CodeForge container. + +| Variable | Description | Default | Set In | +|----------|-------------|---------|--------| +| `ANTHROPIC_MODEL` | Primary Claude model ID | `claude-opus-4-6` | settings.json | +| `ANTHROPIC_DEFAULT_OPUS_MODEL` | Opus model ID | `claude-opus-4-6` | settings.json | +| `ANTHROPIC_DEFAULT_SONNET_MODEL` | Sonnet model ID | `claude-sonnet-4-5-20250929` | settings.json | +| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | Haiku model ID | `claude-haiku-4-5-20251001` | settings.json | +| `CLAUDE_CONFIG_DIR` | Claude Code configuration directory | `/workspaces/.claude` | devcontainer.json | +| `CLAUDE_CODE_MAX_OUTPUT_TOKENS` | Maximum tokens per response | `64000` | settings.json | +| `MAX_THINKING_TOKENS` | Maximum tokens for extended thinking | `63999` | settings.json | +| `CLAUDE_CODE_SHELL` | Shell used for Bash tool execution | `zsh` | settings.json | +| `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` | Context usage percentage that triggers auto-compaction | `95` | settings.json | +| `CLAUDE_CODE_DISABLE_AUTO_MEMORY` | Disable automatic memory features (`0` = enabled) | `0` | settings.json | + +## Agent Teams Variables + +Variables that configure Claude Code's multi-agent team capabilities. + +| Variable | Description | Default | Set In | +|----------|-------------|---------|--------| +| `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` | Enable Agent Teams feature | `1` | settings.json | +| `CLAUDE_CODE_ENABLE_TASKS` | Enable structured task tracking | `true` | settings.json | +| `CLAUDE_CODE_EFFORT_LEVEL` | Response effort level (`low`, `medium`, `high`) | `high` | settings.json | +| `CLAUDE_CODE_PLAN_MODE_INTERVIEW_PHASE` | Enable interview phase in plan mode | `true` | settings.json | +| `CLAUDE_CODE_PLAN_V2_AGENT_COUNT` | Number of agents in plan mode v2 | `3` | settings.json | +| `CLAUDE_CODE_PLAN_MODE_REQUIRED` | Require teammates to run in plan mode until approved | `true` | settings.json | + +## Runtime Limits + +Variables that control timeouts, output sizes, and concurrency. + +| Variable | Description | Default | Set In | +|----------|-------------|---------|--------| +| `BASH_DEFAULT_TIMEOUT_MS` | Default timeout for Bash tool commands (ms) | `240000` | settings.json | +| `BASH_MAX_TIMEOUT_MS` | Maximum allowed Bash timeout (ms) | `600000` | settings.json | +| `BASH_MAX_OUTPUT_LENGTH` | Maximum Bash output length (chars) | `15000` | settings.json | +| `TASK_MAX_OUTPUT_LENGTH` | Maximum Task tool output length (chars) | `64000` | settings.json | +| `MAX_MCP_OUTPUT_TOKENS` | Maximum MCP server output tokens | `10000` | settings.json | +| `MCP_TIMEOUT` | MCP server connection timeout (ms) | `120000` | settings.json | +| `MCP_TOOL_TIMEOUT` | Individual MCP tool call timeout (ms) | `30000` | settings.json | +| `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` | Maximum concurrent tool calls | `5` | settings.json | +| `CLAUDE_CODE_MAX_RETRIES` | Maximum retries for failed API calls | `1` | settings.json | + +## Plugin and Feature Variables + +Variables that control CodeForge's plugin system and features. + +| Variable | Description | Default | Set In | +|----------|-------------|---------|--------| +| `FORCE_AUTOUPDATE_PLUGINS` | Auto-update plugins on session start | `1` | settings.json | +| `ENABLE_TOOL_SEARCH` | Tool search mode and limit | `auto:5` | settings.json | +| `ENABLE_CLAUDE_CODE_SM_COMPACT` | Enable smart compaction | `1` | settings.json | +| `CLAUDE_CODE_FORCE_GLOBAL_CACHE` | Force global prompt cache | `1` | settings.json | + +## Workspace Variables + +Variables set by the DevContainer environment that define workspace paths. + +| Variable | Description | Default | Set In | +|----------|-------------|---------|--------| +| `WORKSPACE_ROOT` | Workspace root directory | `/workspaces` | devcontainer.json | +| `CLAUDE_CONFIG_DIR` | Claude configuration directory | `/workspaces/.claude` | devcontainer.json | +| `GH_CONFIG_DIR` | GitHub CLI configuration directory | `/workspaces/.gh` | devcontainer.json | +| `TMPDIR` | Temporary files directory | `/workspaces/.tmp` | devcontainer.json | +| `CLAUDECODE` | Set to `null` to unset the detection flag, enabling nested Claude Code sessions | `null` | devcontainer.json | + +## Tool-Specific Variables + +Variables that configure individual tools within the container. + +| Variable | Tool | Description | +|----------|------|-------------| +| `CCMS_PROJECT` | ccms | Default project scope for session search | +| `CCMS_FORMAT` | ccms | Default output format (`text`, `json`) | +| `RUFF_CONFIG` | ruff | Path to ruff configuration file | +| `BIOME_CONFIG_PATH` | biome | Path to biome configuration file | + +## Language Runtime Variables + +Variables for language runtimes installed in the container. + +| Variable | Description | +|----------|-------------| +| `UV_PYTHON` | Python version used by uv | +| `VIRTUAL_ENV` | Active virtual environment path | +| `PYTHONPATH` | Python module search path | +| `NVM_DIR` | nvm installation directory | +| `NODE_VERSION` | Active Node.js version | +| `BUN_INSTALL` | Bun installation directory | + +## Setting Environment Variables + +There are four ways to set environment variables, listed from lowest to highest precedence. + +### In devcontainer.json (Container Level) + +Applied when the container is created. Persists across all sessions. + +```json +{ + "remoteEnv": { + "WORKSPACE_ROOT": "/workspaces", + "CLAUDE_CONFIG_DIR": "/workspaces/.claude" + } +} +``` + +### In settings.json (Claude Code Level) + +Applied when Claude Code starts. These are set inside the `env` block. + +```json +{ + "env": { + "ANTHROPIC_MODEL": "claude-sonnet-4-5-20250929", + "CLAUDE_CODE_EFFORT_LEVEL": "medium" + } +} +``` + +### In Shell Profile (User Level) + +Add to `~/.zshrc` or `~/.bashrc`. Applied for every new shell session. + +```bash +export CLAUDE_MODEL="claude-sonnet-4-5-20250929" +``` + +### Per-Session (Highest Precedence) + +Set on the command line when launching Claude Code. Overrides everything else. + +```bash +ANTHROPIC_MODEL="claude-sonnet-4-5-20250929" cc +``` + +## Common Customizations + +Here are the environment variable changes you are most likely to make: + +| Goal | Variable | Value | +|------|----------|-------| +| Use Sonnet instead of Opus | `ANTHROPIC_MODEL` | `claude-sonnet-4-5-20250929` | +| Increase Bash timeout for long builds | `BASH_DEFAULT_TIMEOUT_MS` | `600000` | +| Reduce auto-compact aggressiveness | `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` | `85` | +| Disable extended thinking | (remove `alwaysThinkingEnabled` from settings.json) | -- | +| Limit concurrent tool calls | `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` | `3` | + +## Related + +- [Configuration](../customization/configuration/) -- settings.json structure and file manifest +- [Commands](./commands/) -- commands that use these variables +- [Architecture](./architecture/) -- how configuration layers interact at runtime diff --git a/docs/src/content/docs/reference/index.md b/docs/src/content/docs/reference/index.md new file mode 100644 index 0000000..1dc9b70 --- /dev/null +++ b/docs/src/content/docs/reference/index.md @@ -0,0 +1,83 @@ +--- +title: Reference +description: Technical reference for CodeForge — commands, environment variables, architecture, and changelog. +sidebar: + order: 1 +--- + +This section is a lookup resource for CodeForge internals. Use it when you need the exact name of a command, the default value of an environment variable, or a quick reminder of how components connect. + +## Reference Pages + +| Page | What You Will Find | +|------|-------------------| +| [Commands](./commands/) | Every CLI command and slash command, grouped by category, with usage examples | +| [Environment Variables](./environment/) | All environment variables with types, defaults, and where they are set | +| [Architecture](./architecture/) | System overview, component relationships, data flow, and design principles | +| [Changelog](./changelog/) | Version history from v1.2.0 to current, with migration notes | + +## Most-Used Quick Reference + +### Session Commands + +| Command | What It Does | +|---------|-------------| +| `cc` | Start Claude Code with full CodeForge configuration | +| `ccw` | Start Claude Code in writing mode | +| `ccraw` | Start vanilla Claude Code (no plugins or custom prompt) | +| `ccms "query"` | Search session history | +| `check-setup` | Verify your installation is healthy | + +### Key Paths + +| Path | Purpose | +|------|---------| +| `.devcontainer/config/defaults/settings.json` | Primary configuration file | +| `.devcontainer/config/defaults/main-system-prompt.md` | Main system prompt | +| `.devcontainer/config/file-manifest.json` | Config file deployment rules | +| `.devcontainer/devcontainer.json` | Container definition | +| `.devcontainer/plugins/devs-marketplace/` | Local plugin marketplace | +| `.claude/rules/` | Active rules (deployed from defaults) | +| `.specs/` | Feature specifications | + +### Spec Workflow Commands + +| Command | What It Does | +|---------|-------------| +| `/spec-new ` | Create a new feature spec | +| `/spec-refine ` | Validate assumptions, get user approval | +| `/spec-build ` | Full implementation lifecycle from spec | +| `/spec-review ` | Verify implementation against spec | +| `/spec-update` | As-built spec closure | +| `/spec-check` | Audit spec health | + +## Key Configuration Files + +These are the files you will interact with most often when configuring CodeForge: + +| File | Location | Purpose | +|------|----------|---------| +| `settings.json` | `.devcontainer/config/defaults/` | Model selection, plugin toggles, env vars, permissions | +| `main-system-prompt.md` | `.devcontainer/config/defaults/` | Claude's coding behavior and response style | +| `writing-system-prompt.md` | `.devcontainer/config/defaults/` | Claude's writing mode behavior | +| `file-manifest.json` | `.devcontainer/config/` | Rules for deploying config files to `.claude/` | +| `devcontainer.json` | `.devcontainer/` | Container image, features, mounts, resource limits | +| `hooks.json` | Each plugin's `hooks/` directory | Hook registration for lifecycle automation | +| `plugin.json` | Each plugin's `.claude-plugin/` directory | Plugin manifest and metadata | + +## Inventory at a Glance + +| Component | Count | Details | +|-----------|-------|---------| +| DevContainer features | 21 | Runtimes, CLI tools, monitoring | +| Plugins | 12 | Safety, quality, workflow, intelligence | +| Agents | 17 | Specialized personas from explorer to security-auditor | +| Skills | 34 | On-demand knowledge across coding, testing, frameworks | +| Built-in rules | 3 | Workspace scope, spec workflow, session search | +| CLI commands | 10+ | Session, analysis, code quality, intelligence | + +## Related + +- [Getting Started](../getting-started/) -- setup and first steps +- [Customization](../customization/) -- configuration and extension guides +- [Features](../features/) -- agents, skills, and tools diff --git a/docs/src/styles/global.css b/docs/src/styles/global.css new file mode 100644 index 0000000..684195b --- /dev/null +++ b/docs/src/styles/global.css @@ -0,0 +1,565 @@ +/* CodeForge Documentation — Ember/Charcoal Brand Theme */ + +/* Cascade layer order — MUST be first */ +@layer base, starlight, theme, components, utilities; + +/* Starlight + Tailwind compatibility */ +@import '@astrojs/starlight-tailwind'; + +/* Tailwind v4 */ +@import 'tailwindcss/theme.css' layer(theme); +@import 'tailwindcss/utilities.css' layer(utilities); + +/* Web font */ +@import '@fontsource-variable/plus-jakarta-sans'; + +/* ============================================ + Tailwind v4 Theme Tokens + ============================================ */ +@theme { + /* Typography */ + --font-sans: 'Plus Jakarta Sans Variable', 'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system, sans-serif; + --font-mono: 'JetBrains Mono', 'Fira Code', ui-monospace, monospace; + + /* Ember accent palette */ + --color-ember-50: #fff7ed; + --color-ember-100: #ffedd5; + --color-ember-200: #fed7aa; + --color-ember-300: #fdba74; + --color-ember-400: #fb923c; + --color-ember-500: #f97316; + --color-ember-600: #ea580c; + --color-ember-700: #c2410c; + --color-ember-800: #9a3412; + --color-ember-900: #7c2d12; + --color-ember-950: #431407; + + /* Charcoal/stone palette */ + --color-charcoal-50: #fafaf9; + --color-charcoal-100: #f5f5f4; + --color-charcoal-200: #e7e5e4; + --color-charcoal-300: #d6d3d1; + --color-charcoal-400: #a8a29e; + --color-charcoal-500: #78716c; + --color-charcoal-600: #57534e; + --color-charcoal-700: #44403c; + --color-charcoal-800: #292524; + --color-charcoal-900: #1c1917; + --color-charcoal-950: #0c0a09; +} + +/* ============================================ + Starlight Overrides (UNLAYERED — wins over + Starlight's @layer starlight.base defaults) + ============================================ */ + +/* Dark mode (primary experience) */ +:root { + /* Ember accent scale */ + --sl-color-accent-low: hsl(20, 60%, 14%); + --sl-color-accent: hsl(25, 95%, 53%); + --sl-color-accent-high: hsl(33, 90%, 85%); + + /* Charcoal gray scale */ + --sl-color-gray-1: #f5f5f4; + --sl-color-gray-2: #d6d3d1; + --sl-color-gray-3: #a8a29e; + --sl-color-gray-4: #57534e; + --sl-color-gray-5: #292524; + --sl-color-gray-6: #1c1917; + --sl-color-gray-7: #0c0a09; + + /* Nav & sidebar — semi-transparent for glass effect */ + --sl-color-bg-nav: hsla(20, 14%, 4%, 0.82); + --sl-color-bg-sidebar: hsla(20, 14%, 5%, 0.65); + + /* Hairlines — warm-tinted for brand cohesion */ + --sl-color-hairline-shade: hsla(25, 15%, 22%, 0.5); + --sl-color-hairline-light: hsla(25, 10%, 20%, 0.3); + --sl-color-hairline: hsla(25, 12%, 18%, 0.4); + + /* Fonts */ + --sl-font-system: var(--font-sans); + --sl-font-system-mono: var(--font-mono); + + /* Tighter body text — reduced from previous sizes */ + --sl-text-body: 0.875rem; /* 14px — was 15px */ + --sl-text-body-sm: 0.75rem; /* 12px — was 13px */ + --sl-text-code: 0.75rem; /* 12px — was 13px */ + --sl-text-code-sm: 0.6875rem; /* 11px — was 12px */ + + /* Heading scale — smaller than Starlight defaults */ + --sl-text-h1: 1.625rem; /* 26px — was 28px */ + --sl-text-h2: 1.25rem; /* 20px — was 22px */ + --sl-text-h3: 1.0625rem; /* 17px — was 18px */ + --sl-text-h4: 0.9375rem; /* 15px — was 16px */ + --sl-text-h5: 0.875rem; /* 14px — was 15px */ + + /* Tighter line height — 1.65 instead of 1.75 */ + --sl-line-height: 1.65; + --sl-line-height-headings: 1.25; +} + +/* Desktop heading scale — prevent Starlight's 50em upscaling */ +@media (min-width: 50em) { + :root { + --sl-text-h1: 1.75rem; /* 28px — was 30px */ + --sl-text-h2: 1.375rem; /* 22px — was 24px */ + --sl-text-h3: 1.125rem; /* 18px — was 20px */ + --sl-text-h4: 1rem; /* 16px — was 17px */ + --sl-text-h5: 0.875rem; /* 14px — was 15px */ + } +} + +/* Light mode */ +:root[data-theme='light'] { + --sl-color-accent-low: hsl(30, 70%, 92%); + --sl-color-accent: hsl(25, 90%, 48%); + --sl-color-accent-high: hsl(20, 80%, 28%); + + --sl-color-gray-1: #1c1917; + --sl-color-gray-2: #44403c; + --sl-color-gray-3: #57534e; + --sl-color-gray-4: #a8a29e; + --sl-color-gray-5: #e7e5e4; + --sl-color-gray-6: #f5f5f4; + --sl-color-gray-7: #fafaf9; + + --sl-color-bg-nav: hsla(30, 10%, 98%, 0.82); + --sl-color-bg-sidebar: hsla(30, 10%, 97%, 0.65); + --sl-color-hairline-shade: hsla(25, 8%, 80%, 0.5); + --sl-color-hairline-light: hsla(25, 8%, 85%, 0.4); + --sl-color-hairline: hsla(25, 8%, 82%, 0.45); +} + +/* ============================================ + Nav Bar — Glass Morphism + ============================================ */ + +/* Backdrop blur on the fixed header */ +body header { + backdrop-filter: blur(14px) saturate(1.2); + -webkit-backdrop-filter: blur(14px) saturate(1.2); +} + +/* Hero/splash page — fully transparent nav blending into the dark hero */ +[data-has-hero] { + --sl-color-bg-nav: transparent; + --sl-color-hairline-shade: transparent; +} + +/* ============================================ + Splash Page — Full-Page Dark Background + ============================================ */ +[data-has-hero] .main-frame, +[data-has-hero] .main-pane { + background: var(--color-charcoal-950); +} + +[data-has-hero] main { + background: transparent; +} + +/* ============================================ + Content Typography — Tighter & More Refined + ============================================ */ + +/* H1 — subtle bottom border as section anchor */ +.sl-markdown-content h1:not(:where(.not-content *)) { + font-weight: 700; + letter-spacing: -0.025em; + padding-bottom: 0.4em; + border-bottom: 1px solid var(--sl-color-hairline-light); + margin-bottom: 0.5em; +} + +/* H2 — gradient bottom separator */ +.sl-markdown-content h2:not(:where(.not-content *)) { + font-weight: 650; + letter-spacing: -0.015em; + padding-bottom: 0.3em; + border-bottom: none; + background-image: linear-gradient(to right, var(--sl-color-accent), transparent); + background-size: 100% 1px; + background-position: bottom; + background-repeat: no-repeat; +} + +/* H3, H4 — no borders, just weight differentiation */ +.sl-markdown-content h3:not(:where(.not-content *)) { + font-weight: 600; + letter-spacing: -0.01em; +} + +.sl-markdown-content h4:not(:where(.not-content *)) { + font-weight: 600; +} + +/* Links — cleaner hover with underline reveal */ +.sl-markdown-content a:not(:where(.not-content *)) { + text-decoration: none; + text-underline-offset: 3px; + transition: color 0.15s ease, text-decoration-color 0.15s ease; +} + +.sl-markdown-content a:hover:not(:where(.not-content *)) { + text-decoration: underline; + text-decoration-thickness: 1px; +} + +/* Inline code — slightly tighter padding, rounded, warmer background */ +.sl-markdown-content code:not(:where(.not-content *)):not(pre code) { + border-radius: 4px; + padding: 0.15em 0.35em; + font-size: 0.85em; + background: hsla(25, 20%, 30%, 0.15); + border: 1px solid hsla(25, 15%, 40%, 0.12); +} + +/* Code blocks — rounded with warm border */ +.sl-markdown-content pre:not(:where(.not-content *)) { + border-radius: 8px; + border: 1px solid hsla(25, 15%, 25%, 0.4); + background: hsla(20, 10%, 8%, 0.6); +} + +/* Tables — tighter, more refined */ +.sl-markdown-content table:not(:where(.not-content *)) { + font-size: 0.875em; +} + +.sl-markdown-content th:not(:where(.not-content *)) { + font-size: 0.8em; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +/* Table row hover for scanability */ +.sl-markdown-content tr:not(:where(.not-content *)):hover { + background: hsla(25, 15%, 50%, 0.08); +} + +/* Table header — stronger bottom border + subtle background */ +.sl-markdown-content thead:not(:where(.not-content *)) { + border-bottom: 2px solid var(--sl-color-hairline-shade); +} + +.sl-markdown-content thead th:not(:where(.not-content *)) { + background: hsla(25, 10%, 30%, 0.1); + padding-block: 0.6em; +} + +/* Blockquotes — ember tint on left border */ +.sl-markdown-content blockquote:not(:where(.not-content *)) { + border-inline-start-color: var(--sl-color-accent); + border-inline-start-width: 2px; + opacity: 0.9; +} + +/* Horizontal rules */ +.sl-markdown-content hr:not(:where(.not-content *)) { + border-bottom-color: var(--sl-color-hairline-light); +} + +/* ============================================ + Sidebar Refinements + ============================================ */ + +/* Active sidebar link — ember left-border accent with background */ +nav[aria-label="Main"] a[aria-current="page"], +.sidebar-content a[aria-current="page"] { + border-inline-start: 2px solid var(--sl-color-accent); + padding-inline-start: calc(1rem - 2px); + background: hsla(25, 80%, 50%, 0.08); + border-radius: 0 6px 6px 0; +} + +/* ============================================ + Aside / Callout Refinements + ============================================ */ +.starlight-aside { + border-radius: 8px; + font-size: 0.9rem; +} + +/* Tip aside — ember-themed instead of Starlight purple */ +.starlight-aside--tip { + --sl-color-asides-text-accent: var(--sl-color-accent); + border-color: var(--sl-color-accent); + background: hsla(25, 80%, 50%, 0.06); +} + +/* Note aside — warm slate */ +.starlight-aside--note { + background: hsla(25, 10%, 40%, 0.08); +} + +/* Caution aside — keep warm amber instead of Starlight default */ +.starlight-aside--caution { + background: hsla(38, 80%, 50%, 0.06); +} + +/* ============================================ + Table of Contents — Tighter + ============================================ */ +starlight-toc a { + font-size: 0.8125rem; + line-height: 1.5; +} + +starlight-toc [aria-current="true"] { + font-weight: 600; + color: var(--sl-color-accent); + position: relative; +} + +/* Smooth scrollspy vertical indicator */ +starlight-toc nav { + position: relative; +} + +starlight-toc nav::before { + content: ''; + position: absolute; + inset-inline-start: 0; + top: 0; + bottom: 0; + width: 1px; + background: var(--sl-color-hairline-light); +} + +starlight-toc [aria-current="true"]::before { + content: ''; + position: absolute; + inset-inline-start: calc(-1 * var(--sl-nav-pad-x, 1rem)); + top: 0; + bottom: 0; + width: 2px; + background: var(--sl-color-accent); + border-radius: 1px; +} + +/* ============================================ + Page Title (content-panel heading) + ============================================ */ +.content-panel h1 { + font-size: var(--sl-text-h1); + font-weight: 700; + letter-spacing: -0.025em; +} + +/* ============================================ + Custom Component Styles + ============================================ */ +@layer components { + /* Ember glow effect for hero and accents */ + .ember-glow { + box-shadow: 0 0 60px -12px oklch(0.65 0.2 30 / 0.3); + } + + /* Terminal-style code preview frame */ + .terminal-frame { + background: var(--color-charcoal-900); + border: 1px solid var(--color-charcoal-700); + border-radius: 8px; + overflow: hidden; + } + + .terminal-frame__header { + display: flex; + align-items: center; + gap: 6px; + padding: 10px 14px; + background: var(--color-charcoal-800); + border-bottom: 1px solid var(--color-charcoal-700); + } + + .terminal-frame__dot { + width: 10px; + height: 10px; + border-radius: 50%; + } + + .terminal-frame__body { + padding: 16px 20px; + font-family: var(--font-mono); + font-size: 0.95rem; + line-height: 1.6; + } + + /* Feature card styling */ + .feature-card { + background: var(--color-charcoal-900); + border: 1px solid var(--color-charcoal-800); + border-radius: 12px; + padding: 1.5rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease; + } + + .feature-card:hover { + border-color: var(--color-ember-500); + box-shadow: 0 0 40px -8px oklch(0.65 0.2 30 / 0.25); + transform: translateY(-2px); + } + + /* Animated ember particles for hero */ + @keyframes ember-rise { + 0% { + transform: translateY(0) scale(1); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 0.6; + } + 100% { + transform: translateY(-100vh) scale(0.3); + opacity: 0; + } + } + + @keyframes ember-flicker { + 0%, 100% { + opacity: 0.8; + } + 50% { + opacity: 0.4; + } + } + + @keyframes typing-cursor { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0; + } + } + + @keyframes fade-in-up { + from { + opacity: 0; + transform: translateY(12px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + /* Progressive enhancement: scroll-triggered animations */ + @supports (animation-timeline: view()) { + .sl-markdown-content h2:not(:where(.not-content *)), + .sl-markdown-content h3:not(:where(.not-content *)), + .starlight-aside, + .sl-markdown-content table:not(:where(.not-content *)), + .sl-markdown-content pre:not(:where(.not-content *)) { + animation: fade-in-up 0.4s ease both; + animation-timeline: view(); + animation-range: entry 0% entry 20%; + } + } + + .ember-particle { + position: absolute; + bottom: 0; + width: 4px; + height: 4px; + border-radius: 50%; + background: var(--color-ember-500); + box-shadow: 0 0 6px 2px var(--color-ember-500); + animation: ember-rise linear infinite; + pointer-events: none; + } + + .typing-cursor { + display: inline-block; + width: 2px; + height: 1.1em; + background: var(--color-ember-400); + animation: typing-cursor 1s step-end infinite; + vertical-align: text-bottom; + margin-left: 2px; + } + + /* Agent property badges */ + .badge { + display: inline-flex; + align-items: center; + padding: 0.15em 0.55em; + border-radius: 9999px; + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.01em; + line-height: 1.5; + white-space: nowrap; + } + + .badge--green { + background: hsla(145, 60%, 40%, 0.12); + color: hsl(145, 60%, 65%); + border: 1px solid hsla(145, 50%, 45%, 0.2); + } + + .badge--orange { + background: hsla(25, 80%, 50%, 0.12); + color: hsl(25, 90%, 70%); + border: 1px solid hsla(25, 70%, 50%, 0.2); + } + + .badge--blue { + background: hsla(210, 60%, 50%, 0.12); + color: hsl(210, 70%, 72%); + border: 1px solid hsla(210, 50%, 50%, 0.2); + } + + .badge--purple { + background: hsla(270, 50%, 50%, 0.12); + color: hsl(270, 60%, 75%); + border: 1px solid hsla(270, 40%, 50%, 0.2); + } + + /* Light mode badge adjustments */ + :root[data-theme='light'] .badge--green { + color: hsl(145, 50%, 30%); + background: hsla(145, 50%, 45%, 0.1); + } + :root[data-theme='light'] .badge--orange { + color: hsl(25, 80%, 35%); + background: hsla(25, 70%, 50%, 0.1); + } + :root[data-theme='light'] .badge--blue { + color: hsl(210, 60%, 35%); + background: hsla(210, 50%, 50%, 0.1); + } + :root[data-theme='light'] .badge--purple { + color: hsl(270, 45%, 35%); + background: hsla(270, 40%, 50%, 0.1); + } +} + +/* ============================================ + Accessibility: Respect reduced motion + ============================================ */ +@media (prefers-reduced-motion: reduce) { + .ember-particle { + animation: none; + display: none; + } + + .typing-cursor { + animation: none; + opacity: 1; + } + + .sl-markdown-content h2, + .sl-markdown-content h3, + .starlight-aside, + .sl-markdown-content table, + .sl-markdown-content pre { + animation: none !important; + } +} diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 0000000..bcbf8b5 --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "astro/tsconfigs/strict" +} diff --git a/logos/CodeForgeLogo.png b/logos/CodeForgeLogo.png new file mode 100644 index 0000000..08c13f2 Binary files /dev/null and b/logos/CodeForgeLogo.png differ diff --git a/logos/CodeForgeLogoTr.png b/logos/CodeForgeLogoTr.png new file mode 100644 index 0000000..3a5250b Binary files /dev/null and b/logos/CodeForgeLogoTr.png differ diff --git a/logos/github-avatar.png b/logos/github-avatar.png new file mode 100644 index 0000000..5aab38d Binary files /dev/null and b/logos/github-avatar.png differ diff --git a/package.json b/package.json index f633fe0..a4b0028 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,17 @@ { "name": "codeforge-dev", - "version": "1.13.0", + "version": "1.14.0", "description": "Complete development container that sets up Claude Code with modular devcontainer features, modern dev tools, and persistent configurations. Drop it into any project and get a production-ready AI development environment in minutes.", "main": "setup.js", "bin": { "codeforge": "setup.js" }, "scripts": { - "test": "node test.js" + "test": "node test.js", + "prepublishOnly": "npm test", + "docs:dev": "npm run dev --prefix docs", + "docs:build": "npm run build --prefix docs", + "docs:preview": "npm run preview --prefix docs" }, "keywords": [ "devcontainer", diff --git a/setup.js b/setup.js index 13498c6..116d13f 100644 --- a/setup.js +++ b/setup.js @@ -10,6 +10,7 @@ const DEFAULT_PRESERVE = [ "config/defaults/settings.json", "config/defaults/main-system-prompt.md", "config/defaults/keybindings.json", + "config/defaults/ccstatusline-settings.json", "config/file-manifest.json", ".codeforge-preserve", ]; @@ -244,8 +245,8 @@ function printNextSteps() { function printFeatures() { console.log("Features included:"); console.log(" - Claude Code CLI with optimized tool configuration"); - console.log(" - MCP servers: Qdrant (vector memory), Reasoner"); - console.log(" - Development tools: Node.js LTS, Python 3.14, Go, Bun"); + console.log(" - MCP servers: Qdrant (vector memory)"); + console.log(" - Development tools: Node.js LTS, Python 3.14, Rust, Bun"); console.log(" - Persistent configuration and shell history"); console.log(""); }